1use std::collections::{HashMap, HashSet};
13
14use crate::dialects::DialectType;
15use crate::expressions::{
16 BinaryOp, DataType, DateTimeField, DotAccess, Expression, Function, IfFunc, ListAggOverflow,
17 Literal, Map, Nvl2Func, Struct, StructField, Subscript,
18};
19use crate::schema::{normalize_name, Schema, SchemaError, SchemaResult, TABLE_PARTS};
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
24pub enum TypeCoercionClass {
25 Text = 0,
27 Numeric = 1,
29 Timelike = 2,
31}
32
33impl TypeCoercionClass {
34 pub fn from_data_type(dt: &DataType) -> Option<Self> {
36 match dt {
37 DataType::Char { .. }
39 | DataType::VarChar { .. }
40 | DataType::Text
41 | DataType::Binary { .. }
42 | DataType::VarBinary { .. }
43 | DataType::Blob => Some(TypeCoercionClass::Text),
44
45 DataType::Boolean
47 | DataType::TinyInt { .. }
48 | DataType::SmallInt { .. }
49 | DataType::Int { .. }
50 | DataType::BigInt { .. }
51 | DataType::Int128
52 | DataType::UInt8
53 | DataType::UInt16
54 | DataType::UInt32
55 | DataType::UInt64
56 | DataType::UInt128
57 | DataType::Float { .. }
58 | DataType::Double { .. }
59 | DataType::Decimal { .. } => Some(TypeCoercionClass::Numeric),
60
61 DataType::Date
63 | DataType::Time { .. }
64 | DataType::Timestamp { .. }
65 | DataType::Interval { .. } => Some(TypeCoercionClass::Timelike),
66
67 _ => None,
69 }
70 }
71}
72
73pub struct TypeAnnotator<'a> {
75 _schema: Option<&'a dyn Schema>,
77 _dialect: Option<DialectType>,
79 annotate_aggregates: bool,
81 function_return_types: HashMap<String, DataType>,
83}
84
85impl<'a> TypeAnnotator<'a> {
86 pub fn new(schema: Option<&'a dyn Schema>, dialect: Option<DialectType>) -> Self {
88 let mut annotator = Self {
89 _schema: schema,
90 _dialect: dialect,
91 annotate_aggregates: true,
92 function_return_types: HashMap::new(),
93 };
94 annotator.init_function_return_types();
95 annotator
96 }
97
98 fn init_function_return_types(&mut self) {
100 self.function_return_types
102 .insert("COUNT".to_string(), DataType::BigInt { length: None });
103 self.function_return_types.insert(
104 "SUM".to_string(),
105 DataType::Decimal {
106 precision: None,
107 scale: None,
108 },
109 );
110 self.function_return_types.insert(
111 "AVG".to_string(),
112 DataType::Double {
113 precision: None,
114 scale: None,
115 },
116 );
117
118 if self._dialect == Some(DialectType::DuckDB) {
120 for name in [
125 "ARRAY_TO_STRING",
126 "ARRAY_TO_STRING_COMMA_DEFAULT",
127 "MONTHNAME",
128 "DAYNAME",
129 ] {
130 self.function_return_types.insert(
131 name.to_string(),
132 DataType::VarChar {
133 length: None,
134 parenthesized_length: false,
135 },
136 );
137 }
138 }
139 self.function_return_types.insert(
140 "CONCAT".to_string(),
141 DataType::VarChar {
142 length: None,
143 parenthesized_length: false,
144 },
145 );
146 self.function_return_types.insert(
147 "UPPER".to_string(),
148 DataType::VarChar {
149 length: None,
150 parenthesized_length: false,
151 },
152 );
153 self.function_return_types.insert(
154 "LOWER".to_string(),
155 DataType::VarChar {
156 length: None,
157 parenthesized_length: false,
158 },
159 );
160 self.function_return_types.insert(
161 "TRIM".to_string(),
162 DataType::VarChar {
163 length: None,
164 parenthesized_length: false,
165 },
166 );
167 self.function_return_types.insert(
168 "LTRIM".to_string(),
169 DataType::VarChar {
170 length: None,
171 parenthesized_length: false,
172 },
173 );
174 self.function_return_types.insert(
175 "RTRIM".to_string(),
176 DataType::VarChar {
177 length: None,
178 parenthesized_length: false,
179 },
180 );
181 self.function_return_types.insert(
182 "SUBSTRING".to_string(),
183 DataType::VarChar {
184 length: None,
185 parenthesized_length: false,
186 },
187 );
188 self.function_return_types.insert(
189 "SUBSTR".to_string(),
190 DataType::VarChar {
191 length: None,
192 parenthesized_length: false,
193 },
194 );
195 self.function_return_types.insert(
196 "REPLACE".to_string(),
197 DataType::VarChar {
198 length: None,
199 parenthesized_length: false,
200 },
201 );
202 self.function_return_types.insert(
203 "LENGTH".to_string(),
204 DataType::Int {
205 length: None,
206 integer_spelling: false,
207 },
208 );
209 self.function_return_types.insert(
210 "CHAR_LENGTH".to_string(),
211 DataType::Int {
212 length: None,
213 integer_spelling: false,
214 },
215 );
216
217 self.function_return_types.insert(
219 "NOW".to_string(),
220 DataType::Timestamp {
221 precision: None,
222 timezone: false,
223 },
224 );
225 self.function_return_types.insert(
226 "CURRENT_TIMESTAMP".to_string(),
227 DataType::Timestamp {
228 precision: None,
229 timezone: false,
230 },
231 );
232 self.function_return_types
233 .insert("CURRENT_DATE".to_string(), DataType::Date);
234 self.function_return_types.insert(
235 "CURRENT_TIME".to_string(),
236 DataType::Time {
237 precision: None,
238 timezone: false,
239 },
240 );
241 self.function_return_types
242 .insert("DATE".to_string(), DataType::Date);
243 self.function_return_types.insert(
244 "YEAR".to_string(),
245 DataType::Int {
246 length: None,
247 integer_spelling: false,
248 },
249 );
250 self.function_return_types.insert(
251 "MONTH".to_string(),
252 DataType::Int {
253 length: None,
254 integer_spelling: false,
255 },
256 );
257 self.function_return_types.insert(
258 "DAY".to_string(),
259 DataType::Int {
260 length: None,
261 integer_spelling: false,
262 },
263 );
264 self.function_return_types.insert(
265 "HOUR".to_string(),
266 DataType::Int {
267 length: None,
268 integer_spelling: false,
269 },
270 );
271 self.function_return_types.insert(
272 "MINUTE".to_string(),
273 DataType::Int {
274 length: None,
275 integer_spelling: false,
276 },
277 );
278 self.function_return_types.insert(
279 "SECOND".to_string(),
280 DataType::Int {
281 length: None,
282 integer_spelling: false,
283 },
284 );
285 self.function_return_types.insert(
286 "EXTRACT".to_string(),
287 DataType::Int {
288 length: None,
289 integer_spelling: false,
290 },
291 );
292 self.function_return_types.insert(
293 "DATE_DIFF".to_string(),
294 DataType::Int {
295 length: None,
296 integer_spelling: false,
297 },
298 );
299 self.function_return_types.insert(
300 "DATEDIFF".to_string(),
301 DataType::Int {
302 length: None,
303 integer_spelling: false,
304 },
305 );
306
307 self.function_return_types.insert(
309 "ABS".to_string(),
310 DataType::Double {
311 precision: None,
312 scale: None,
313 },
314 );
315 self.function_return_types.insert(
316 "ROUND".to_string(),
317 DataType::Double {
318 precision: None,
319 scale: None,
320 },
321 );
322 self.function_return_types.insert(
323 "DATE_FORMAT".to_string(),
324 DataType::VarChar {
325 length: None,
326 parenthesized_length: false,
327 },
328 );
329 self.function_return_types.insert(
330 "FORMAT_DATE".to_string(),
331 DataType::VarChar {
332 length: None,
333 parenthesized_length: false,
334 },
335 );
336 self.function_return_types.insert(
337 "TIME_TO_STR".to_string(),
338 DataType::VarChar {
339 length: None,
340 parenthesized_length: false,
341 },
342 );
343 self.function_return_types.insert(
344 "SQRT".to_string(),
345 DataType::Double {
346 precision: None,
347 scale: None,
348 },
349 );
350 self.function_return_types.insert(
351 "POWER".to_string(),
352 DataType::Double {
353 precision: None,
354 scale: None,
355 },
356 );
357 self.function_return_types.insert(
358 "MOD".to_string(),
359 DataType::Int {
360 length: None,
361 integer_spelling: false,
362 },
363 );
364 self.function_return_types.insert(
365 "LOG".to_string(),
366 DataType::Double {
367 precision: None,
368 scale: None,
369 },
370 );
371 self.function_return_types.insert(
372 "LN".to_string(),
373 DataType::Double {
374 precision: None,
375 scale: None,
376 },
377 );
378 self.function_return_types.insert(
379 "EXP".to_string(),
380 DataType::Double {
381 precision: None,
382 scale: None,
383 },
384 );
385
386 self.function_return_types
388 .insert("COALESCE".to_string(), DataType::Unknown);
389 self.function_return_types
390 .insert("NULLIF".to_string(), DataType::Unknown);
391 self.function_return_types
392 .insert("GREATEST".to_string(), DataType::Unknown);
393 self.function_return_types
394 .insert("LEAST".to_string(), DataType::Unknown);
395 }
396
397 pub fn annotate(&mut self, expr: &Expression) -> Option<DataType> {
399 match expr {
400 Expression::Literal(lit) => self.annotate_literal(lit),
402 Expression::Boolean(_) => Some(DataType::Boolean),
403 Expression::Null(_) => None, Expression::Add(op)
407 | Expression::Sub(op)
408 | Expression::Mul(op)
409 | Expression::Mod(op) => self.annotate_arithmetic(op, false),
410 Expression::Div(op) => self.annotate_arithmetic(op, true),
411
412 Expression::Eq(_)
414 | Expression::Neq(_)
415 | Expression::Lt(_)
416 | Expression::Lte(_)
417 | Expression::Gt(_)
418 | Expression::Gte(_)
419 | Expression::Like(_)
420 | Expression::ILike(_) => Some(DataType::Boolean),
421
422 Expression::And(_) | Expression::Or(_) | Expression::Not(_) => Some(DataType::Boolean),
424
425 Expression::Between(_)
427 | Expression::In(_)
428 | Expression::IsNull(_)
429 | Expression::IsTrue(_)
430 | Expression::IsFalse(_)
431 | Expression::Is(_)
432 | Expression::Exists(_) => Some(DataType::Boolean),
433
434 Expression::Concat(_) => Some(DataType::VarChar {
436 length: None,
437 parenthesized_length: false,
438 }),
439
440 Expression::BitwiseAnd(_)
442 | Expression::BitwiseOr(_)
443 | Expression::BitwiseXor(_)
444 | Expression::BitwiseNot(_) => Some(DataType::BigInt { length: None }),
445
446 Expression::Neg(op) => self.annotate(&op.this),
448
449 Expression::Paren(paren) => self.annotate(&paren.this),
451 Expression::Annotated(annotated) => self.annotate(&annotated.this),
452
453 Expression::Function(func) => self.annotate_function(func),
455 Expression::IfFunc(if_func) => self.annotate_if_func(if_func),
456 Expression::Nvl2(nvl2) => self.annotate_nvl2(nvl2),
457 Expression::Coalesce(coalesce) => self.coerce_arg_types(&coalesce.expressions),
458
459 Expression::Count(_) => Some(DataType::BigInt { length: None }),
461 Expression::Sum(agg) => self.annotate_sum(&agg.this),
462 Expression::SumIf(f) => self.annotate_sum(&f.this),
463 Expression::Avg(_) => Some(DataType::Double {
464 precision: None,
465 scale: None,
466 }),
467 Expression::Min(agg) => self.annotate(&agg.this),
468 Expression::Max(agg) => self.annotate(&agg.this),
469 Expression::Median(agg) => {
470 if self._dialect == Some(DialectType::DuckDB) {
471 self.annotate_duckdb_median(&agg.this)
472 } else {
473 None
474 }
475 }
476 Expression::GroupConcat(_) | Expression::StringAgg(_) | Expression::ListAgg(_) => {
477 Some(DataType::VarChar {
478 length: None,
479 parenthesized_length: false,
480 })
481 }
482
483 Expression::AggregateFunction(agg) => {
485 if !self.annotate_aggregates {
486 return None;
487 }
488 let func_name = agg.name.to_uppercase();
489 self.get_aggregate_return_type(&func_name, &agg.args)
490 }
491
492 Expression::Column(col) => {
494 if let Some(schema) = &self._schema {
495 let table_name = col.table.as_ref().map(|t| t.name.as_str()).unwrap_or("");
496 schema.get_column_type(table_name, &col.name.name).ok()
497 } else {
498 None
499 }
500 }
501
502 Expression::Cast(cast) => Some(cast.to.clone()),
504 Expression::SafeCast(cast) => Some(cast.to.clone()),
505 Expression::TryCast(cast) => Some(cast.to.clone()),
506
507 Expression::Subquery(subq) => {
509 if let Expression::Select(select) = &subq.this {
510 if let Some(first) = select.expressions.first() {
511 self.annotate(first)
512 } else {
513 None
514 }
515 } else {
516 None
517 }
518 }
519
520 Expression::Case(case) => self.coerce_expression_types(
522 case.whens
523 .iter()
524 .map(|(_, result)| result)
525 .chain(case.else_.iter()),
526 ),
527
528 Expression::Array(arr) => self.annotate_array(&arr.expressions),
531 Expression::ArrayFunc(arr) => self.annotate_array(&arr.expressions),
532
533 Expression::Interval(_) => Some(DataType::Interval {
535 unit: None,
536 to: None,
537 }),
538
539 Expression::WindowFunction(window) => self.annotate(&window.this),
541
542 Expression::CurrentDate(_) => Some(DataType::Date),
544 Expression::CurrentTime(_) => Some(DataType::Time {
545 precision: None,
546 timezone: false,
547 }),
548 Expression::CurrentTimestamp(_) | Expression::CurrentTimestampLTZ(_) => {
549 Some(DataType::Timestamp {
550 precision: None,
551 timezone: false,
552 })
553 }
554
555 Expression::DateAdd(_)
557 | Expression::DateSub(_)
558 | Expression::ToDate(_)
559 | Expression::Date(_) => Some(DataType::Date),
560 Expression::DateDiff(_) => Some(DataType::Int {
561 length: None,
562 integer_spelling: false,
563 }),
564 Expression::Extract(extract) if matches!(self._dialect, Some(DialectType::DuckDB)) => {
565 let fractional = match &extract.field {
567 DateTimeField::Epoch => true,
568 DateTimeField::Custom(name) => {
569 name.eq_ignore_ascii_case("epoch") || name.eq_ignore_ascii_case("julian")
570 }
571 _ => false,
572 };
573 Some(if fractional {
574 DataType::Double {
575 precision: None,
576 scale: None,
577 }
578 } else {
579 DataType::BigInt { length: None }
580 })
581 }
582 Expression::Extract(_) => Some(DataType::Int {
583 length: None,
584 integer_spelling: false,
585 }),
586 Expression::ToTimestamp(_) => Some(DataType::Timestamp {
587 precision: None,
588 timezone: false,
589 }),
590
591 Expression::Upper(_)
593 | Expression::Lower(_)
594 | Expression::Trim(_)
595 | Expression::LTrim(_)
596 | Expression::RTrim(_)
597 | Expression::Replace(_)
598 | Expression::Substring(_)
599 | Expression::Reverse(_)
600 | Expression::Left(_)
601 | Expression::Right(_)
602 | Expression::Repeat(_)
603 | Expression::Lpad(_)
604 | Expression::Rpad(_)
605 | Expression::ConcatWs(_)
606 | Expression::Overlay(_) => Some(DataType::VarChar {
607 length: None,
608 parenthesized_length: false,
609 }),
610 Expression::Length(_) => Some(DataType::Int {
611 length: None,
612 integer_spelling: false,
613 }),
614
615 Expression::Abs(_)
617 | Expression::Sqrt(_)
618 | Expression::Cbrt(_)
619 | Expression::Ln(_)
620 | Expression::Exp(_)
621 | Expression::Power(_)
622 | Expression::Log(_) => Some(DataType::Double {
623 precision: None,
624 scale: None,
625 }),
626 Expression::Round(_) => Some(DataType::Double {
627 precision: None,
628 scale: None,
629 }),
630 Expression::Floor(f) => self.annotate_math_function(&f.this),
631 Expression::Ceil(f) => self.annotate_math_function(&f.this),
632 Expression::Sign(s) => self.annotate(&s.this),
633 Expression::DateFormat(_) | Expression::FormatDate(_) | Expression::TimeToStr(_) => {
634 Some(DataType::VarChar {
635 length: None,
636 parenthesized_length: false,
637 })
638 }
639
640 Expression::Greatest(v) | Expression::Least(v) => self.coerce_arg_types(&v.expressions),
642
643 Expression::Alias(alias) => self.annotate(&alias.this),
645
646 Expression::Select(_) => None,
648
649 Expression::Subscript(sub) => self.annotate_subscript(sub),
653
654 Expression::Dot(dot) => self.annotate_dot(dot),
656
657 Expression::Struct(s) => self.annotate_struct(s),
661
662 Expression::Map(map) => self.annotate_map(map),
666 Expression::MapFromEntries(mfe) => {
667 if let Some(DataType::Array { element_type, .. }) = self.annotate(&mfe.this) {
669 if let DataType::Struct { fields, .. } = *element_type {
670 if fields.len() >= 2 {
671 return Some(DataType::Map {
672 key_type: Box::new(fields[0].data_type.clone()),
673 value_type: Box::new(fields[1].data_type.clone()),
674 });
675 }
676 }
677 }
678 Some(DataType::Map {
679 key_type: Box::new(DataType::Unknown),
680 value_type: Box::new(DataType::Unknown),
681 })
682 }
683
684 Expression::Union(union) => self.annotate_set_operation(&union.left, &union.right),
688 Expression::Intersect(intersect) => {
689 self.annotate_set_operation(&intersect.left, &intersect.right)
690 }
691 Expression::Except(except) => self.annotate_set_operation(&except.left, &except.right),
692
693 Expression::Lateral(lateral) => {
697 self.annotate(&lateral.this)
699 }
700 Expression::LateralView(lv) => {
701 self.annotate_lateral_view(lv)
703 }
704 Expression::Unnest(unnest) => {
705 if let Some(DataType::Array { element_type, .. }) = self.annotate(&unnest.this) {
707 Some(*element_type)
708 } else {
709 None
710 }
711 }
712 Expression::Explode(explode) => {
713 if let Some(DataType::Array { element_type, .. }) = self.annotate(&explode.this) {
715 Some(*element_type)
716 } else if let Some(DataType::Map {
717 key_type,
718 value_type,
719 }) = self.annotate(&explode.this)
720 {
721 Some(DataType::Struct {
723 fields: vec![
724 StructField::new("key".to_string(), *key_type),
725 StructField::new("value".to_string(), *value_type),
726 ],
727 nested: false,
728 })
729 } else {
730 None
731 }
732 }
733 Expression::ExplodeOuter(explode) => {
734 if let Some(DataType::Array { element_type, .. }) = self.annotate(&explode.this) {
736 Some(*element_type)
737 } else {
738 None
739 }
740 }
741 Expression::GenerateSeries(gs) => {
742 if let Some(ref start) = gs.start {
744 self.annotate(start)
745 } else if let Some(ref end) = gs.end {
746 self.annotate(end)
747 } else {
748 Some(DataType::Int {
749 length: None,
750 integer_spelling: false,
751 })
752 }
753 }
754
755 _ => None,
757 }
758 }
759
760 pub fn annotate_in_place(&mut self, expr: &mut Expression) {
766 self.annotate_children_in_place(expr);
768
769 let dt = self.annotate(expr);
773
774 if let Some(data_type) = dt {
776 expr.set_inferred_type(data_type);
777 }
778 }
779
780 fn annotate_children_in_place(&mut self, expr: &mut Expression) {
782 match expr {
783 Expression::And(op)
785 | Expression::Or(op)
786 | Expression::Add(op)
787 | Expression::Sub(op)
788 | Expression::Mul(op)
789 | Expression::Div(op)
790 | Expression::Mod(op)
791 | Expression::Eq(op)
792 | Expression::Neq(op)
793 | Expression::Lt(op)
794 | Expression::Lte(op)
795 | Expression::Gt(op)
796 | Expression::Gte(op)
797 | Expression::Concat(op)
798 | Expression::BitwiseAnd(op)
799 | Expression::BitwiseOr(op)
800 | Expression::BitwiseXor(op)
801 | Expression::Adjacent(op)
802 | Expression::TsMatch(op)
803 | Expression::PropertyEQ(op)
804 | Expression::ArrayContainsAll(op)
805 | Expression::ArrayContainedBy(op)
806 | Expression::ArrayOverlaps(op)
807 | Expression::JSONBContainsAllTopKeys(op)
808 | Expression::JSONBContainsAnyTopKeys(op)
809 | Expression::JSONBDeleteAtPath(op)
810 | Expression::ExtendsLeft(op)
811 | Expression::ExtendsRight(op)
812 | Expression::Is(op)
813 | Expression::MemberOf(op)
814 | Expression::Match(op)
815 | Expression::NullSafeEq(op)
816 | Expression::NullSafeNeq(op)
817 | Expression::Glob(op)
818 | Expression::BitwiseLeftShift(op)
819 | Expression::BitwiseRightShift(op) => {
820 self.annotate_in_place(&mut op.left);
821 self.annotate_in_place(&mut op.right);
822 }
823
824 Expression::Like(op) | Expression::ILike(op) => {
826 self.annotate_in_place(&mut op.left);
827 self.annotate_in_place(&mut op.right);
828 }
829
830 Expression::Not(op) | Expression::Neg(op) | Expression::BitwiseNot(op) => {
832 self.annotate_in_place(&mut op.this);
833 }
834
835 Expression::Cast(c) | Expression::TryCast(c) | Expression::SafeCast(c) => {
837 self.annotate_in_place(&mut c.this);
838 }
839
840 Expression::Paren(paren) => {
842 self.annotate_in_place(&mut paren.this);
843 }
844 Expression::Annotated(annotated) => {
845 self.annotate_in_place(&mut annotated.this);
846 }
847
848 Expression::Case(c) => {
850 if let Some(ref mut operand) = c.operand {
851 self.annotate_in_place(operand);
852 }
853 for (cond, then_expr) in &mut c.whens {
854 self.annotate_in_place(cond);
855 self.annotate_in_place(then_expr);
856 }
857 if let Some(ref mut else_expr) = c.else_ {
858 self.annotate_in_place(else_expr);
859 }
860 }
861
862 Expression::Array(a) => {
864 for expression in &mut a.expressions {
865 self.annotate_in_place(expression);
866 }
867 }
868 Expression::ArrayFunc(a) => {
869 for expression in &mut a.expressions {
870 self.annotate_in_place(expression);
871 }
872 }
873
874 Expression::Alias(a) => {
876 self.annotate_in_place(&mut a.this);
877 }
878
879 Expression::Column(_) => {}
881
882 Expression::Dot(dot) => {
884 self.annotate_in_place(&mut dot.this);
885 }
886
887 Expression::Function(f) => {
889 for arg in &mut f.args {
890 self.annotate_in_place(arg);
891 }
892 }
893 Expression::Unnest(unnest) => {
894 self.annotate_in_place(&mut unnest.this);
895 for expression in &mut unnest.expressions {
896 self.annotate_in_place(expression);
897 }
898 }
899
900 Expression::IfFunc(f) => {
902 self.annotate_in_place(&mut f.condition);
903 self.annotate_in_place(&mut f.true_value);
904 if let Some(false_value) = &mut f.false_value {
905 self.annotate_in_place(false_value);
906 }
907 }
908 Expression::Nvl2(f) => {
909 self.annotate_in_place(&mut f.this);
910 self.annotate_in_place(&mut f.true_value);
911 self.annotate_in_place(&mut f.false_value);
912 }
913
914 Expression::AggregateFunction(f) => {
916 for arg in &mut f.args {
917 self.annotate_in_place(arg);
918 }
919 }
920
921 Expression::Count(f) => {
923 if let Some(this) = &mut f.this {
924 self.annotate_in_place(this);
925 }
926 if let Some(filter) = &mut f.filter {
927 self.annotate_in_place(filter);
928 }
929 }
930 Expression::GroupConcat(f) => {
931 self.annotate_in_place(&mut f.this);
932 if let Some(separator) = &mut f.separator {
933 self.annotate_in_place(separator);
934 }
935 if let Some(order_by) = &mut f.order_by {
936 for ordered in order_by {
937 self.annotate_in_place(&mut ordered.this);
938 }
939 }
940 if let Some(filter) = &mut f.filter {
941 self.annotate_in_place(filter);
942 }
943 }
944 Expression::StringAgg(f) => {
945 self.annotate_in_place(&mut f.this);
946 if let Some(separator) = &mut f.separator {
947 self.annotate_in_place(separator);
948 }
949 if let Some(order_by) = &mut f.order_by {
950 for ordered in order_by {
951 self.annotate_in_place(&mut ordered.this);
952 }
953 }
954 if let Some(filter) = &mut f.filter {
955 self.annotate_in_place(filter);
956 }
957 if let Some(limit) = &mut f.limit {
958 self.annotate_in_place(limit);
959 }
960 }
961 Expression::ListAgg(f) => {
962 self.annotate_in_place(&mut f.this);
963 if let Some(separator) = &mut f.separator {
964 self.annotate_in_place(separator);
965 }
966 if let Some(order_by) = &mut f.order_by {
967 for ordered in order_by {
968 self.annotate_in_place(&mut ordered.this);
969 }
970 }
971 if let Some(filter) = &mut f.filter {
972 self.annotate_in_place(filter);
973 }
974 if let Some(ListAggOverflow::Truncate {
975 filler: Some(filler),
976 ..
977 }) = &mut f.on_overflow
978 {
979 self.annotate_in_place(filler);
980 }
981 }
982 Expression::SumIf(f) => {
983 self.annotate_in_place(&mut f.this);
984 self.annotate_in_place(&mut f.condition);
985 if let Some(filter) = &mut f.filter {
986 self.annotate_in_place(filter);
987 }
988 }
989
990 Expression::WindowFunction(w) => {
992 self.annotate_in_place(&mut w.this);
993 }
994
995 Expression::Subquery(s) => {
997 self.annotate_in_place(&mut s.this);
998 }
999
1000 Expression::Trim(f) => {
1001 self.annotate_in_place(&mut f.this);
1002 if let Some(characters) = &mut f.characters {
1003 self.annotate_in_place(characters);
1004 }
1005 }
1006
1007 Expression::Upper(f)
1009 | Expression::Lower(f)
1010 | Expression::Length(f)
1011 | Expression::LTrim(f)
1012 | Expression::RTrim(f)
1013 | Expression::Reverse(f)
1014 | Expression::Abs(f)
1015 | Expression::Sqrt(f)
1016 | Expression::Cbrt(f)
1017 | Expression::Ln(f)
1018 | Expression::Exp(f)
1019 | Expression::Sign(f)
1020 | Expression::Date(f)
1021 | Expression::Time(f)
1022 | Expression::Explode(f)
1023 | Expression::ExplodeOuter(f)
1024 | Expression::MapFromEntries(f)
1025 | Expression::MapKeys(f)
1026 | Expression::MapValues(f)
1027 | Expression::ArrayLength(f)
1028 | Expression::ArraySize(f)
1029 | Expression::Cardinality(f)
1030 | Expression::ArrayReverse(f)
1031 | Expression::ArrayDistinct(f)
1032 | Expression::ArrayFlatten(f)
1033 | Expression::ArrayCompact(f)
1034 | Expression::ToArray(f)
1035 | Expression::JsonArrayLength(f)
1036 | Expression::JsonKeys(f)
1037 | Expression::JsonType(f)
1038 | Expression::ParseJson(f)
1039 | Expression::ToJson(f)
1040 | Expression::Year(f)
1041 | Expression::Month(f)
1042 | Expression::Day(f)
1043 | Expression::Hour(f)
1044 | Expression::Minute(f)
1045 | Expression::Second(f)
1046 | Expression::Initcap(f)
1047 | Expression::Ascii(f)
1048 | Expression::Chr(f)
1049 | Expression::Soundex(f)
1050 | Expression::ByteLength(f)
1051 | Expression::Hex(f)
1052 | Expression::LowerHex(f)
1053 | Expression::Unicode(f)
1054 | Expression::Typeof(f)
1055 | Expression::BitwiseCount(f)
1056 | Expression::Epoch(f)
1057 | Expression::EpochMs(f)
1058 | Expression::Radians(f)
1059 | Expression::Degrees(f)
1060 | Expression::Sin(f)
1061 | Expression::Cos(f)
1062 | Expression::Tan(f)
1063 | Expression::Asin(f)
1064 | Expression::Acos(f)
1065 | Expression::Atan(f)
1066 | Expression::IsNan(f)
1067 | Expression::IsInf(f) => {
1068 self.annotate_in_place(&mut f.this);
1069 }
1070
1071 Expression::Power(f)
1073 | Expression::NullIf(f)
1074 | Expression::IfNull(f)
1075 | Expression::Nvl(f)
1076 | Expression::Contains(f)
1077 | Expression::StartsWith(f)
1078 | Expression::EndsWith(f)
1079 | Expression::Levenshtein(f)
1080 | Expression::ModFunc(f)
1081 | Expression::IntDiv(f)
1082 | Expression::Atan2(f)
1083 | Expression::AddMonths(f)
1084 | Expression::MonthsBetween(f)
1085 | Expression::NextDay(f)
1086 | Expression::UnixToTimeStr(f)
1087 | Expression::ArrayContains(f)
1088 | Expression::ArrayPosition(f)
1089 | Expression::ArrayAppend(f)
1090 | Expression::ArrayPrepend(f)
1091 | Expression::ArrayUnion(f)
1092 | Expression::ArrayExcept(f)
1093 | Expression::ArrayRemove(f)
1094 | Expression::StarMap(f)
1095 | Expression::MapFromArrays(f)
1096 | Expression::MapContainsKey(f)
1097 | Expression::ElementAt(f)
1098 | Expression::JsonMergePatch(f) => {
1099 self.annotate_in_place(&mut f.this);
1100 self.annotate_in_place(&mut f.expression);
1101 }
1102
1103 Expression::Coalesce(f)
1105 | Expression::Greatest(f)
1106 | Expression::Least(f)
1107 | Expression::ArrayConcat(f)
1108 | Expression::ArrayIntersect(f)
1109 | Expression::ArrayZip(f)
1110 | Expression::MapConcat(f)
1111 | Expression::JsonArray(f) => {
1112 for e in &mut f.expressions {
1113 self.annotate_in_place(e);
1114 }
1115 }
1116
1117 Expression::Sum(f)
1119 | Expression::Avg(f)
1120 | Expression::Min(f)
1121 | Expression::Max(f)
1122 | Expression::ArrayAgg(f)
1123 | Expression::CountIf(f)
1124 | Expression::Stddev(f)
1125 | Expression::StddevPop(f)
1126 | Expression::StddevSamp(f)
1127 | Expression::Variance(f)
1128 | Expression::VarPop(f)
1129 | Expression::VarSamp(f)
1130 | Expression::Median(f)
1131 | Expression::Mode(f)
1132 | Expression::First(f)
1133 | Expression::Last(f)
1134 | Expression::AnyValue(f)
1135 | Expression::ApproxDistinct(f)
1136 | Expression::ApproxCountDistinct(f)
1137 | Expression::LogicalAnd(f)
1138 | Expression::LogicalOr(f)
1139 | Expression::Skewness(f)
1140 | Expression::ArrayConcatAgg(f)
1141 | Expression::ArrayUniqueAgg(f)
1142 | Expression::BoolXorAgg(f)
1143 | Expression::BitwiseAndAgg(f)
1144 | Expression::BitwiseOrAgg(f)
1145 | Expression::BitwiseXorAgg(f) => {
1146 self.annotate_in_place(&mut f.this);
1147 }
1148
1149 Expression::Select(s) => {
1151 for e in &mut s.expressions {
1152 self.annotate_in_place(e);
1153 }
1154 }
1155
1156 _ => {}
1158 }
1159 }
1160
1161 fn annotate_math_function(&mut self, arg: &Expression) -> Option<DataType> {
1164 let input_type = self.annotate(arg)?;
1165 match input_type {
1166 DataType::TinyInt { .. }
1167 | DataType::SmallInt { .. }
1168 | DataType::Int { .. }
1169 | DataType::BigInt { .. } => Some(DataType::Double {
1170 precision: None,
1171 scale: None,
1172 }),
1173 other => Some(other),
1174 }
1175 }
1176
1177 fn annotate_subscript(&mut self, sub: &Subscript) -> Option<DataType> {
1179 let base_type = self.annotate(&sub.this)?;
1180
1181 match base_type {
1182 DataType::Array { element_type, .. } => Some(*element_type),
1183 DataType::Map { value_type, .. } => Some(*value_type),
1184 DataType::Json | DataType::JsonB => Some(DataType::Json), DataType::VarChar { .. } | DataType::Text => {
1186 Some(DataType::VarChar {
1188 length: Some(1),
1189 parenthesized_length: false,
1190 })
1191 }
1192 _ => None,
1193 }
1194 }
1195
1196 fn annotate_dot(&mut self, dot: &DotAccess) -> Option<DataType> {
1198 let base_type = self.annotate(&dot.this)?;
1199 let DataType::Struct { fields, .. } = base_type else {
1200 return None;
1201 };
1202 let field_name = normalize_name(&dot.field.name, self._dialect, false, true);
1203
1204 fields
1205 .into_iter()
1206 .find(|field| normalize_name(&field.name, self._dialect, false, true) == field_name)
1207 .map(|field| field.data_type)
1208 }
1209
1210 fn annotate_struct(&mut self, s: &Struct) -> Option<DataType> {
1212 let fields: Vec<StructField> = s
1213 .fields
1214 .iter()
1215 .map(|(name, expr)| {
1216 let field_type = self.annotate(expr).unwrap_or(DataType::Unknown);
1217 StructField::new(name.clone().unwrap_or_default(), field_type)
1218 })
1219 .collect();
1220 Some(DataType::Struct {
1221 fields,
1222 nested: false,
1223 })
1224 }
1225
1226 fn annotate_map(&mut self, map: &Map) -> Option<DataType> {
1228 let key_type = if let Some(first_key) = map.keys.first() {
1229 self.annotate(first_key).unwrap_or(DataType::Unknown)
1230 } else {
1231 DataType::Unknown
1232 };
1233
1234 let value_type = if let Some(first_value) = map.values.first() {
1235 self.annotate(first_value).unwrap_or(DataType::Unknown)
1236 } else {
1237 DataType::Unknown
1238 };
1239
1240 Some(DataType::Map {
1241 key_type: Box::new(key_type),
1242 value_type: Box::new(value_type),
1243 })
1244 }
1245
1246 fn annotate_set_operation(
1249 &mut self,
1250 _left: &Expression,
1251 _right: &Expression,
1252 ) -> Option<DataType> {
1253 None
1257 }
1258
1259 fn annotate_lateral_view(&mut self, lv: &crate::expressions::LateralView) -> Option<DataType> {
1261 self.annotate(&lv.this)
1263 }
1264
1265 fn annotate_literal(&self, lit: &Literal) -> Option<DataType> {
1267 match lit {
1268 Literal::String(_)
1269 | Literal::NationalString(_)
1270 | Literal::TripleQuotedString(_, _)
1271 | Literal::EscapeString(_)
1272 | Literal::DollarString(_)
1273 | Literal::RawString(_) => Some(DataType::VarChar {
1274 length: None,
1275 parenthesized_length: false,
1276 }),
1277 Literal::Number(n) => {
1278 if n.contains('.') || n.contains('e') || n.contains('E') {
1280 Some(DataType::Double {
1281 precision: None,
1282 scale: None,
1283 })
1284 } else {
1285 if let Ok(_) = n.parse::<i32>() {
1287 Some(DataType::Int {
1288 length: None,
1289 integer_spelling: false,
1290 })
1291 } else {
1292 Some(DataType::BigInt { length: None })
1293 }
1294 }
1295 }
1296 Literal::HexString(_) | Literal::BitString(_) | Literal::ByteString(_) => {
1297 Some(DataType::VarBinary { length: None })
1298 }
1299 Literal::HexNumber(_) => Some(DataType::BigInt { length: None }),
1300 Literal::Date(_) => Some(DataType::Date),
1301 Literal::Time(_) => Some(DataType::Time {
1302 precision: None,
1303 timezone: false,
1304 }),
1305 Literal::Timestamp(_) => Some(DataType::Timestamp {
1306 precision: None,
1307 timezone: false,
1308 }),
1309 Literal::Datetime(_) => Some(DataType::Custom {
1310 name: "DATETIME".to_string(),
1311 }),
1312 }
1313 }
1314
1315 fn annotate_arithmetic(&mut self, op: &BinaryOp, division: bool) -> Option<DataType> {
1317 let left_type = self.annotate(&op.left);
1318 let right_type = self.annotate(&op.right);
1319
1320 match (left_type, right_type) {
1321 (Some(l), Some(r)) => {
1322 if self._dialect == Some(DialectType::DuckDB) {
1323 if division && (is_unsigned_integer(&l) || is_unsigned_integer(&r)) {
1324 return Some(double_type());
1325 }
1326 if let Some(result) = duckdb_unsigned_integer_coercion(&l, &r, true) {
1327 return Some(result);
1328 }
1329 }
1330 self.coerce_types(&l, &r)
1331 }
1332 (Some(t), None) | (None, Some(t)) => Some(t),
1333 (None, None) => None,
1334 }
1335 }
1336
1337 fn annotate_function(&mut self, func: &Function) -> Option<DataType> {
1339 let func_name = func.name.to_uppercase();
1340
1341 if self._dialect == Some(DialectType::DuckDB) && !func.quoted {
1342 match func_name.as_str() {
1343 "SUM" => return func.args.first().and_then(|arg| self.annotate_sum(arg)),
1346 "COALESCE" | "IFNULL" => return self.coerce_arg_types(&func.args),
1347 "DATE_TRUNC" => return self.annotate_duckdb_date_trunc(func),
1348 "REGEXP_EXTRACT_ALL" => return self.annotate_duckdb_regexp_extract_all(func),
1349 _ => {}
1350 }
1351 }
1352
1353 if let Some(return_type) = self.function_return_types.get(&func_name) {
1355 if *return_type != DataType::Unknown {
1356 return Some(return_type.clone());
1357 }
1358 }
1359
1360 match func_name.as_str() {
1362 "UNNEST" => func.args.first().and_then(|arg| match self.annotate(arg) {
1363 Some(DataType::Array { element_type, .. }) => Some(*element_type),
1364 _ => None,
1365 }),
1366 "COALESCE" | "IFNULL" | "NVL" | "ISNULL" => {
1367 for arg in &func.args {
1369 if let Some(arg_type) = self.annotate(arg) {
1370 return Some(arg_type);
1371 }
1372 }
1373 None
1374 }
1375 "NULLIF" => {
1376 func.args.first().and_then(|arg| self.annotate(arg))
1378 }
1379 "GREATEST" | "LEAST" => {
1380 self.coerce_arg_types(&func.args)
1382 }
1383 "IF" | "IIF" => {
1384 if func.args.len() >= 2 {
1386 self.annotate(&func.args[1])
1387 } else {
1388 None
1389 }
1390 }
1391 _ => {
1392 func.args.first().and_then(|arg| self.annotate(arg))
1394 }
1395 }
1396 }
1397
1398 fn annotate_duckdb_regexp_extract_all(&mut self, func: &Function) -> Option<DataType> {
1401 if !(2..=4).contains(&func.args.len()) {
1402 return None;
1403 }
1404
1405 fn unwrap(mut expr: &Expression) -> &Expression {
1406 loop {
1407 expr = match expr {
1408 Expression::Paren(p) => &p.this,
1409 Expression::Annotated(a) => &a.this,
1410 _ => return expr,
1411 };
1412 }
1413 }
1414
1415 let varchar = DataType::VarChar {
1416 length: None,
1417 parenthesized_length: false,
1418 };
1419 let element_type = if let Some(group) = func.args.get(2).map(unwrap) {
1420 let names = match group {
1421 Expression::Array(a) => Some(&a.expressions),
1422 Expression::ArrayFunc(a) => Some(&a.expressions),
1423 _ => None,
1424 };
1425 if let Some(names) = names {
1426 if names.is_empty() {
1427 return None;
1428 }
1429 let mut seen = HashSet::new();
1430 let mut fields = Vec::with_capacity(names.len());
1431 for name in names {
1432 let Expression::Literal(literal) = unwrap(name) else {
1433 return None;
1434 };
1435 if !literal.is_string() {
1436 return None;
1437 }
1438 let name = literal.value_str();
1439 if !seen.insert(name.to_ascii_lowercase()) {
1442 return None;
1443 }
1444 fields.push(StructField::new(name.to_string(), varchar.clone()));
1445 }
1446 DataType::Struct {
1447 fields,
1448 nested: false,
1449 }
1450 } else if matches!(group, Expression::Null(_))
1451 || matches!(
1452 self.annotate(group),
1453 Some(
1454 DataType::TinyInt { .. } | DataType::SmallInt { .. } | DataType::Int { .. }
1455 )
1456 )
1457 {
1458 varchar
1459 } else {
1460 return None;
1463 }
1464 } else {
1465 varchar
1466 };
1467 Some(DataType::Array {
1468 element_type: Box::new(element_type),
1469 dimension: None,
1470 })
1471 }
1472
1473 fn annotate_duckdb_date_trunc(&mut self, func: &Function) -> Option<DataType> {
1475 if func.args.len() != 2 {
1476 return None;
1477 }
1478
1479 match self.annotate(&func.args[1])? {
1480 DataType::Date => Some(DataType::Timestamp {
1481 precision: None,
1482 timezone: false,
1483 }),
1484 DataType::Timestamp { timezone, .. } => Some(DataType::Timestamp {
1485 precision: None,
1486 timezone,
1487 }),
1488 DataType::Interval { .. } => Some(DataType::Interval {
1489 unit: None,
1490 to: None,
1491 }),
1492 _ => None,
1493 }
1494 }
1495
1496 fn annotate_if_func(&mut self, func: &IfFunc) -> Option<DataType> {
1498 let true_type = self.annotate(&func.true_value);
1499 let false_type = func
1500 .false_value
1501 .as_ref()
1502 .and_then(|expr| self.annotate(expr));
1503
1504 match (true_type, false_type) {
1505 (Some(left), Some(right)) => self.coerce_types(&left, &right),
1506 (Some(dt), None) | (None, Some(dt)) => Some(dt),
1507 (None, None) => None,
1508 }
1509 }
1510
1511 fn annotate_nvl2(&mut self, func: &Nvl2Func) -> Option<DataType> {
1513 let true_type = self.annotate(&func.true_value);
1514 let false_type = self.annotate(&func.false_value);
1515
1516 match (true_type, false_type) {
1517 (Some(left), Some(right)) => self.coerce_types(&left, &right),
1518 (Some(dt), None) | (None, Some(dt)) => Some(dt),
1519 (None, None) => None,
1520 }
1521 }
1522
1523 fn get_aggregate_return_type(
1525 &mut self,
1526 func_name: &str,
1527 args: &[Expression],
1528 ) -> Option<DataType> {
1529 match func_name {
1530 "COUNT" | "COUNT_IF" => Some(DataType::BigInt { length: None }),
1531 "SUM_IF" => {
1532 if let Some(arg) = args.first() {
1533 self.annotate_sum(arg)
1534 } else {
1535 Some(DataType::Decimal {
1536 precision: None,
1537 scale: None,
1538 })
1539 }
1540 }
1541 "SUM" => {
1542 if let Some(arg) = args.first() {
1543 self.annotate_sum(arg)
1544 } else {
1545 Some(DataType::Decimal {
1546 precision: None,
1547 scale: None,
1548 })
1549 }
1550 }
1551 "AVG" => Some(DataType::Double {
1552 precision: None,
1553 scale: None,
1554 }),
1555 "MIN" | "MAX" => {
1556 let input_type = args.first().and_then(|arg| self.annotate(arg));
1560 if args.len() == 2 {
1561 input_type.map(|element_type| DataType::Array {
1562 element_type: Box::new(element_type),
1563 dimension: None,
1564 })
1565 } else {
1566 input_type
1567 }
1568 }
1569 "STRING_AGG" | "GROUP_CONCAT" | "LISTAGG" | "ARRAY_AGG" => Some(DataType::VarChar {
1570 length: None,
1571 parenthesized_length: false,
1572 }),
1573 "BOOL_AND" | "BOOL_OR" | "EVERY" | "ANY" | "SOME" => Some(DataType::Boolean),
1574 "BIT_AND" | "BIT_OR" | "BIT_XOR" => Some(DataType::BigInt { length: None }),
1575 "STDDEV" | "STDDEV_POP" | "STDDEV_SAMP" | "VARIANCE" | "VAR_POP" | "VAR_SAMP" => {
1576 Some(DataType::Double {
1577 precision: None,
1578 scale: None,
1579 })
1580 }
1581 "PERCENTILE_CONT" | "PERCENTILE_DISC" => {
1582 args.first().and_then(|arg| self.annotate(arg))
1583 }
1584 "MEDIAN" => args.first().and_then(|arg| {
1585 if self._dialect == Some(DialectType::DuckDB) {
1586 self.annotate_duckdb_median(arg)
1587 } else {
1588 self.annotate(arg)
1589 }
1590 }),
1591 _ => None,
1592 }
1593 }
1594
1595 fn annotate_duckdb_median(&mut self, arg: &Expression) -> Option<DataType> {
1600 match self.annotate(arg)? {
1601 DataType::TinyInt { .. }
1602 | DataType::SmallInt { .. }
1603 | DataType::Int { .. }
1604 | DataType::BigInt { .. }
1605 | DataType::Int128 => Some(DataType::Double {
1606 precision: None,
1607 scale: None,
1608 }),
1609 DataType::UInt8
1610 | DataType::UInt16
1611 | DataType::UInt32
1612 | DataType::UInt64
1613 | DataType::UInt128 => Some(double_type()),
1614 DataType::Date => Some(DataType::Timestamp {
1615 precision: None,
1616 timezone: false,
1617 }),
1618 DataType::Unknown => None,
1619 other => Some(other),
1620 }
1621 }
1622
1623 fn annotate_sum(&mut self, arg: &Expression) -> Option<DataType> {
1625 let arg_type = self.annotate(arg);
1626 if self._dialect == Some(DialectType::DuckDB) {
1627 return match arg_type? {
1630 DataType::Boolean
1631 | DataType::TinyInt { .. }
1632 | DataType::SmallInt { .. }
1633 | DataType::Int { .. }
1634 | DataType::BigInt { .. }
1635 | DataType::Int128
1636 | DataType::UInt8
1637 | DataType::UInt16
1638 | DataType::UInt32
1639 | DataType::UInt64 => Some(DataType::Int128),
1640 DataType::UInt128 | DataType::Float { .. } | DataType::Double { .. } => {
1641 Some(double_type())
1642 }
1643 DataType::Decimal { precision, scale } => Some(DataType::Decimal {
1644 precision: Some(38),
1645 scale: Some(scale.unwrap_or(if precision.is_some() { 0 } else { 3 })),
1647 }),
1648 _ => None,
1650 };
1651 }
1652 match arg_type {
1653 Some(DataType::TinyInt { .. })
1654 | Some(DataType::SmallInt { .. })
1655 | Some(DataType::Int { .. }) => Some(DataType::BigInt { length: None }),
1656 Some(DataType::BigInt { .. }) => Some(DataType::BigInt { length: None }),
1657 Some(DataType::Int128) => Some(DataType::Int128),
1658 Some(DataType::Float { .. }) | Some(DataType::Double { .. }) => {
1659 Some(DataType::Double {
1660 precision: None,
1661 scale: None,
1662 })
1663 }
1664 Some(DataType::Decimal { precision, scale }) => {
1665 Some(DataType::Decimal { precision, scale })
1666 }
1667 _ => Some(DataType::Decimal {
1668 precision: None,
1669 scale: None,
1670 }),
1671 }
1672 }
1673
1674 fn annotate_array(&mut self, expressions: &[Expression]) -> Option<DataType> {
1676 let element_type = self
1677 .coerce_expression_types(expressions.iter())
1678 .unwrap_or(DataType::Unknown);
1679 Some(DataType::Array {
1680 element_type: Box::new(element_type),
1681 dimension: None,
1682 })
1683 }
1684
1685 fn coerce_arg_types(&mut self, args: &[Expression]) -> Option<DataType> {
1687 self.coerce_expression_types(args.iter())
1688 }
1689
1690 fn coerce_expression_types<'b>(
1692 &mut self,
1693 args: impl IntoIterator<Item = &'b Expression>,
1694 ) -> Option<DataType> {
1695 let mut result_type: Option<DataType> = None;
1696 for arg in args {
1697 if let Some(arg_type) = self.annotate(arg) {
1698 result_type = match result_type {
1699 Some(t) => self.coerce_types(&t, &arg_type),
1700 None => Some(arg_type),
1701 };
1702 }
1703 }
1704 result_type
1705 }
1706
1707 fn coerce_types(&self, left: &DataType, right: &DataType) -> Option<DataType> {
1709 if left == right {
1711 return Some(left.clone());
1712 }
1713
1714 if let (
1716 DataType::Array {
1717 element_type: left_element,
1718 dimension: left_dimension,
1719 },
1720 DataType::Array {
1721 element_type: right_element,
1722 dimension: right_dimension,
1723 },
1724 ) = (left, right)
1725 {
1726 return self
1727 .coerce_types(left_element, right_element)
1728 .map(|element_type| DataType::Array {
1729 element_type: Box::new(element_type),
1730 dimension: if left_dimension == right_dimension {
1731 *left_dimension
1732 } else {
1733 None
1734 },
1735 });
1736 }
1737
1738 match (left, right) {
1740 (DataType::Date, DataType::Interval { .. })
1741 | (DataType::Interval { .. }, DataType::Date) => return Some(DataType::Date),
1742 (
1743 DataType::Timestamp {
1744 precision,
1745 timezone,
1746 },
1747 DataType::Interval { .. },
1748 )
1749 | (
1750 DataType::Interval { .. },
1751 DataType::Timestamp {
1752 precision,
1753 timezone,
1754 },
1755 ) => {
1756 return Some(DataType::Timestamp {
1757 precision: *precision,
1758 timezone: *timezone,
1759 });
1760 }
1761 _ => {}
1762 }
1763
1764 let left_class = TypeCoercionClass::from_data_type(left);
1766 let right_class = TypeCoercionClass::from_data_type(right);
1767
1768 match (left_class, right_class) {
1769 (Some(lc), Some(rc)) if lc == rc => {
1771 if lc == TypeCoercionClass::Numeric {
1773 Some(self.wider_numeric_type(left, right))
1774 } else {
1775 Some(left.clone())
1777 }
1778 }
1779 (Some(lc), Some(rc)) => {
1781 if lc > rc {
1782 Some(left.clone())
1783 } else {
1784 Some(right.clone())
1785 }
1786 }
1787 (Some(_), None) => Some(left.clone()),
1789 (None, Some(_)) => Some(right.clone()),
1790 (None, None) => Some(DataType::Unknown),
1792 }
1793 }
1794
1795 fn wider_numeric_type(&self, left: &DataType, right: &DataType) -> DataType {
1797 if self._dialect == Some(DialectType::DuckDB) {
1798 if let Some(result) = duckdb_unsigned_integer_coercion(left, right, false) {
1799 return result;
1800 }
1801 }
1802 let order = |dt: &DataType| -> u8 {
1803 match dt {
1804 DataType::Boolean => 0,
1805 DataType::TinyInt { .. } | DataType::UInt8 => 1,
1806 DataType::SmallInt { .. } | DataType::UInt16 => 2,
1807 DataType::Int { .. } | DataType::UInt32 => 3,
1808 DataType::BigInt { .. } | DataType::UInt64 => 4,
1809 DataType::Int128 | DataType::UInt128 => 5,
1810 DataType::Float { .. } => 6,
1811 DataType::Double { .. } => 7,
1812 DataType::Decimal { .. } => 8,
1813 _ => 0,
1814 }
1815 };
1816
1817 if order(left) >= order(right) {
1818 left.clone()
1819 } else {
1820 right.clone()
1821 }
1822 }
1823}
1824
1825fn double_type() -> DataType {
1826 DataType::Double {
1827 precision: None,
1828 scale: None,
1829 }
1830}
1831
1832fn is_unsigned_integer(data_type: &DataType) -> bool {
1833 matches!(
1834 data_type,
1835 DataType::UInt8
1836 | DataType::UInt16
1837 | DataType::UInt32
1838 | DataType::UInt64
1839 | DataType::UInt128
1840 )
1841}
1842
1843fn integer_shape(data_type: &DataType) -> Option<(u16, bool)> {
1845 Some(match data_type {
1846 DataType::Boolean => (0, false),
1847 DataType::TinyInt { .. } => (8, false),
1848 DataType::SmallInt { .. } => (16, false),
1849 DataType::Int { .. } => (32, false),
1850 DataType::BigInt { .. } => (64, false),
1851 DataType::Int128 => (128, false),
1852 DataType::UInt8 => (8, true),
1853 DataType::UInt16 => (16, true),
1854 DataType::UInt32 => (32, true),
1855 DataType::UInt64 => (64, true),
1856 DataType::UInt128 => (128, true),
1857 _ => return None,
1858 })
1859}
1860
1861fn signed_integer_type(bits: u16) -> DataType {
1862 match bits {
1863 0..=8 => DataType::TinyInt { length: None },
1864 9..=16 => DataType::SmallInt { length: None },
1865 17..=32 => DataType::Int {
1866 length: None,
1867 integer_spelling: false,
1868 },
1869 33..=64 => DataType::BigInt { length: None },
1870 65..=128 => DataType::Int128,
1871 _ => double_type(),
1872 }
1873}
1874
1875fn duckdb_unsigned_integer_coercion(
1878 left: &DataType,
1879 right: &DataType,
1880 arithmetic: bool,
1881) -> Option<DataType> {
1882 let (left_bits, left_unsigned) = integer_shape(left)?;
1883 let (right_bits, right_unsigned) = integer_shape(right)?;
1884 if !left_unsigned && !right_unsigned {
1885 return None;
1886 }
1887 if left_unsigned && right_unsigned {
1888 return Some(if left_bits >= right_bits { left } else { right }.clone());
1889 }
1890 let (signed, unsigned, signed_type, unsigned_type) = if left_unsigned {
1891 (right_bits, left_bits, right, left)
1892 } else {
1893 (left_bits, right_bits, left, right)
1894 };
1895 if signed == 0 && !arithmetic {
1896 return Some(unsigned_type.clone());
1897 }
1898 if signed > unsigned {
1899 return Some(signed_type.clone());
1900 }
1901 if unsigned == 128 {
1902 return Some(if arithmetic {
1906 double_type()
1907 } else {
1908 signed_integer_type(signed + 1)
1909 });
1910 }
1911 let required_bits = unsigned + 1;
1912 Some(signed_integer_type(if arithmetic {
1913 required_bits.max(64)
1914 } else {
1915 required_bits
1916 }))
1917}
1918
1919struct ScopedSchema<'a> {
1924 parent: Option<&'a dyn Schema>,
1925 tables: HashMap<String, HashMap<String, DataType>>,
1926 dialect: Option<DialectType>,
1927}
1928
1929impl<'a> ScopedSchema<'a> {
1930 fn new(parent: Option<&'a dyn Schema>, dialect: Option<DialectType>) -> Self {
1931 Self {
1932 parent,
1933 tables: HashMap::new(),
1934 dialect,
1935 }
1936 }
1937
1938 fn normalized(&self, name: &str, is_table: bool) -> String {
1939 normalize_name(name, self.dialect, is_table, true)
1940 }
1941
1942 fn local_column_type(&self, table: &str, column: &str) -> Option<DataType> {
1943 let table = self.normalized(table, true);
1944 let column = self.normalized(column, false);
1945 self.tables
1946 .get(&table)
1947 .and_then(|columns| columns.get(&column))
1948 .cloned()
1949 }
1950
1951 fn local_tables_for_column(&self, column: &str) -> Vec<String> {
1952 let column = self.normalized(column, false);
1953 self.tables
1954 .iter()
1955 .filter_map(|(table, columns)| columns.contains_key(&column).then(|| table.clone()))
1956 .collect()
1957 }
1958}
1959
1960impl Schema for ScopedSchema<'_> {
1961 fn dialect(&self) -> Option<DialectType> {
1962 self.dialect
1963 .or_else(|| self.parent.and_then(Schema::dialect))
1964 }
1965
1966 fn add_table(
1967 &mut self,
1968 table: &str,
1969 columns: &[(String, DataType)],
1970 _dialect: Option<DialectType>,
1971 ) -> SchemaResult<()> {
1972 let table = self.normalized(table, true);
1973 let columns = columns
1974 .iter()
1975 .map(|(name, data_type)| (self.normalized(name, false), data_type.clone()))
1976 .collect();
1977 self.tables.insert(table, columns);
1978 Ok(())
1979 }
1980
1981 fn column_names(&self, table: &str) -> SchemaResult<Vec<String>> {
1982 let table = self.normalized(table, true);
1983 if let Some(columns) = self.tables.get(&table) {
1984 return Ok(columns.keys().cloned().collect());
1985 }
1986 self.parent
1987 .ok_or_else(|| SchemaError::TableNotFound(table.clone()))?
1988 .column_names(&table)
1989 }
1990
1991 fn get_column_type(&self, table: &str, column: &str) -> SchemaResult<DataType> {
1992 if table.is_empty() {
1993 let local_tables = self.local_tables_for_column(column);
1994 return match local_tables.as_slice() {
1995 [local_table] => self.get_column_type(local_table, column),
1996 [] => self
1997 .parent
1998 .ok_or_else(|| SchemaError::ColumnNotFound {
1999 table: String::new(),
2000 column: column.to_string(),
2001 })?
2002 .get_column_type(table, column),
2003 _ => Err(SchemaError::AmbiguousTable {
2004 table: String::new(),
2005 matches: local_tables.join(", "),
2006 }),
2007 };
2008 }
2009
2010 let normalized_table = self.normalized(table, true);
2011 if self.tables.contains_key(&normalized_table) {
2012 return self.local_column_type(table, column).ok_or_else(|| {
2013 SchemaError::ColumnNotFound {
2014 table: table.to_string(),
2015 column: column.to_string(),
2016 }
2017 });
2018 }
2019
2020 self.parent
2021 .ok_or_else(|| SchemaError::ColumnNotFound {
2022 table: table.to_string(),
2023 column: column.to_string(),
2024 })?
2025 .get_column_type(table, column)
2026 }
2027
2028 fn has_column(&self, table: &str, column: &str) -> bool {
2029 self.get_column_type(table, column).is_ok()
2030 }
2031
2032 fn supported_table_args(&self) -> &[&str] {
2033 TABLE_PARTS
2034 }
2035
2036 fn is_empty(&self) -> bool {
2037 self.tables.is_empty() && self.parent.is_none_or(Schema::is_empty)
2038 }
2039
2040 fn depth(&self) -> usize {
2041 self.parent.map_or(1, |schema| schema.depth().max(1))
2042 }
2043
2044 fn find_tables_for_column(&self, column: &str) -> Vec<String> {
2045 let mut tables = self.local_tables_for_column(column);
2046 if let Some(parent) = self.parent {
2047 tables.extend(parent.find_tables_for_column(column));
2048 }
2049 let mut seen = HashSet::new();
2050 tables.retain(|table| seen.insert(table.clone()));
2051 tables
2052 }
2053}
2054
2055type OutputColumns = Vec<(String, DataType)>;
2056
2057fn table_name(table: &crate::expressions::TableRef) -> String {
2058 let mut parts = Vec::new();
2059 if let Some(catalog) = &table.catalog {
2060 parts.push(catalog.name.as_str());
2061 }
2062 if let Some(schema) = &table.schema {
2063 parts.push(schema.name.as_str());
2064 }
2065 parts.push(table.name.name.as_str());
2066 parts.join(".")
2067}
2068
2069fn table_columns(schema: &dyn Schema, table: &str) -> OutputColumns {
2070 schema
2071 .column_names(table)
2072 .unwrap_or_default()
2073 .into_iter()
2074 .map(|column| {
2075 let data_type = schema
2076 .get_column_type(table, &column)
2077 .unwrap_or(DataType::Unknown);
2078 (column, data_type)
2079 })
2080 .collect()
2081}
2082
2083fn apply_column_aliases(
2084 mut columns: OutputColumns,
2085 aliases: &[crate::expressions::Identifier],
2086) -> OutputColumns {
2087 for ((name, _), alias) in columns.iter_mut().zip(aliases) {
2088 *name = alias.name.clone();
2089 }
2090 columns
2091}
2092
2093fn projection_name(expression: &Expression) -> Option<String> {
2094 match expression {
2095 Expression::Alias(alias) => Some(alias.alias.name.clone()),
2096 Expression::Column(column) => Some(column.name.name.clone()),
2097 Expression::Identifier(identifier) => Some(identifier.name.clone()),
2098 _ => None,
2099 }
2100}
2101
2102fn projection_type(expression: &Expression) -> DataType {
2103 expression
2104 .inferred_type()
2105 .or_else(|| match expression {
2106 Expression::Alias(alias) => alias.this.inferred_type(),
2107 _ => None,
2108 })
2109 .cloned()
2110 .unwrap_or(DataType::Unknown)
2111}
2112
2113fn query_outputs(expressions: &[Expression]) -> OutputColumns {
2114 expressions
2115 .iter()
2116 .filter_map(|expression| {
2117 projection_name(expression).map(|name| (name, projection_type(expression)))
2118 })
2119 .collect()
2120}
2121
2122fn array_element_type(data_type: Option<&DataType>) -> DataType {
2123 match data_type {
2124 Some(DataType::Array { element_type, .. }) => (**element_type).clone(),
2125 _ => DataType::Unknown,
2126 }
2127}
2128
2129fn unnest_output_types(unnest: &crate::expressions::UnnestFunc) -> Vec<DataType> {
2130 let mut types = vec![array_element_type(unnest.this.inferred_type())];
2131 types.extend(
2132 unnest
2133 .expressions
2134 .iter()
2135 .map(|expression| array_element_type(expression.inferred_type())),
2136 );
2137 if unnest.with_ordinality || unnest.offset_alias.is_some() {
2138 types.push(DataType::BigInt { length: None });
2139 }
2140 types
2141}
2142
2143fn virtual_output_columns(
2144 expression: &Expression,
2145 source_alias: &str,
2146 column_aliases: &[crate::expressions::Identifier],
2147) -> OutputColumns {
2148 let (types, offset_alias) = match expression {
2149 Expression::Unnest(unnest) => (unnest_output_types(unnest), unnest.offset_alias.as_ref()),
2150 Expression::Explode(explode) | Expression::ExplodeOuter(explode) => {
2151 (vec![array_element_type(explode.this.inferred_type())], None)
2152 }
2153 Expression::Function(function) if function.name.eq_ignore_ascii_case("UNNEST") => (
2154 function
2155 .args
2156 .iter()
2157 .map(|argument| array_element_type(argument.inferred_type()))
2158 .collect(),
2159 None,
2160 ),
2161 _ => return Vec::new(),
2162 };
2163
2164 if column_aliases.is_empty() {
2165 let mut columns = Vec::new();
2166 if let Some(data_type) = types.first() {
2167 columns.push((source_alias.to_string(), data_type.clone()));
2168 }
2169 if let Some(offset_alias) = offset_alias {
2170 columns.push((offset_alias.name.clone(), DataType::BigInt { length: None }));
2171 }
2172 columns
2173 } else {
2174 column_aliases
2175 .iter()
2176 .zip(types)
2177 .map(|(alias, data_type)| (alias.name.clone(), data_type))
2178 .collect()
2179 }
2180}
2181
2182fn annotate_relation_source(
2183 expression: &mut Expression,
2184 schema: &mut ScopedSchema<'_>,
2185 dialect: Option<DialectType>,
2186) {
2187 match expression {
2188 Expression::Table(table) => {
2189 let source_table = table_name(table);
2190 let mut columns = table_columns(schema, &source_table);
2191 columns = apply_column_aliases(columns, &table.column_aliases);
2192 let visible_name = table
2193 .alias
2194 .as_ref()
2195 .map(|alias| alias.name.as_str())
2196 .unwrap_or(table.name.name.as_str());
2197 let _ = schema.add_table(visible_name, &columns, dialect);
2198 }
2199 Expression::Subquery(subquery) => {
2200 let mut columns = annotate_scoped_expression(&mut subquery.this, Some(schema), dialect);
2201 columns = apply_column_aliases(columns, &subquery.column_aliases);
2202 if let Some((_, first_type)) = columns.first() {
2203 subquery.inferred_type = Some(first_type.clone());
2204 }
2205 if let Some(alias) = &subquery.alias {
2206 let _ = schema.add_table(&alias.name, &columns, dialect);
2207 }
2208 }
2209 Expression::Alias(alias) => {
2210 match &mut alias.this {
2211 Expression::Subquery(subquery) => {
2212 let columns =
2213 annotate_scoped_expression(&mut subquery.this, Some(schema), dialect);
2214 let columns = apply_column_aliases(columns, &alias.column_aliases);
2215 let _ = schema.add_table(&alias.alias.name, &columns, dialect);
2216 return;
2217 }
2218 _ => {
2219 let mut annotator = TypeAnnotator::new(Some(schema), dialect);
2220 annotator.annotate_in_place(&mut alias.this);
2221 }
2222 }
2223 let columns =
2224 virtual_output_columns(&alias.this, &alias.alias.name, &alias.column_aliases);
2225 if !columns.is_empty() {
2226 let _ = schema.add_table(&alias.alias.name, &columns, dialect);
2227 }
2228 }
2229 Expression::Unnest(_) => {
2230 let mut annotator = TypeAnnotator::new(Some(schema), dialect);
2231 annotator.annotate_in_place(expression);
2232 if let Expression::Unnest(unnest) = expression {
2233 if let Some(alias) = &unnest.alias {
2234 let alias_name = alias.name.clone();
2235 let columns = unnest_output_types(unnest)
2236 .into_iter()
2237 .next()
2238 .map(|data_type| vec![(alias_name.clone(), data_type)])
2239 .unwrap_or_default();
2240 let _ = schema.add_table(&alias_name, &columns, dialect);
2241 }
2242 }
2243 }
2244 Expression::Lateral(lateral) => {
2245 let mut annotator = TypeAnnotator::new(Some(schema), dialect);
2246 annotator.annotate_in_place(&mut lateral.this);
2247 if let Some(alias) = &lateral.alias {
2248 let aliases: Vec<_> = lateral
2249 .column_aliases
2250 .iter()
2251 .map(crate::expressions::Identifier::new)
2252 .collect();
2253 let columns = virtual_output_columns(&lateral.this, alias, &aliases);
2254 if !columns.is_empty() {
2255 let _ = schema.add_table(alias, &columns, dialect);
2256 }
2257 }
2258 }
2259 Expression::Paren(paren) => annotate_relation_source(&mut paren.this, schema, dialect),
2260 _ => {
2261 let mut annotator = TypeAnnotator::new(Some(schema), dialect);
2262 annotator.annotate_in_place(expression);
2263 }
2264 }
2265}
2266
2267fn annotate_with(
2268 with: &mut Option<crate::expressions::With>,
2269 schema: &mut ScopedSchema<'_>,
2270 dialect: Option<DialectType>,
2271) {
2272 if let Some(with) = with {
2273 for cte in &mut with.ctes {
2274 let columns = annotate_scoped_expression(&mut cte.this, Some(schema), dialect);
2275 let columns = apply_column_aliases(columns, &cte.columns);
2276 let _ = schema.add_table(&cte.alias.name, &columns, dialect);
2277 }
2278 }
2279}
2280
2281fn annotate_select(
2282 select: &mut crate::expressions::Select,
2283 parent: Option<&dyn Schema>,
2284 dialect: Option<DialectType>,
2285) -> OutputColumns {
2286 let mut schema = ScopedSchema::new(parent, dialect);
2287 annotate_with(&mut select.with, &mut schema, dialect);
2288
2289 if let Some(from) = &mut select.from {
2290 for source in &mut from.expressions {
2291 annotate_relation_source(source, &mut schema, dialect);
2292 }
2293 }
2294 for join in &mut select.joins {
2295 annotate_relation_source(&mut join.this, &mut schema, dialect);
2296 }
2297
2298 let mut annotator = TypeAnnotator::new(Some(&schema), dialect);
2299 for expression in &mut select.expressions {
2300 annotator.annotate_in_place(expression);
2301 }
2302 query_outputs(&select.expressions)
2303}
2304
2305fn annotate_scoped_expression(
2306 expression: &mut Expression,
2307 parent: Option<&dyn Schema>,
2308 dialect: Option<DialectType>,
2309) -> OutputColumns {
2310 match expression {
2311 Expression::Select(select) => annotate_select(select, parent, dialect),
2312 Expression::Subquery(subquery) => {
2313 let columns = annotate_scoped_expression(&mut subquery.this, parent, dialect);
2314 if let Some((_, first_type)) = columns.first() {
2315 subquery.inferred_type = Some(first_type.clone());
2316 }
2317 columns
2318 }
2319 Expression::Cte(cte) => annotate_scoped_expression(&mut cte.this, parent, dialect),
2320 Expression::Paren(paren) => annotate_scoped_expression(&mut paren.this, parent, dialect),
2321 Expression::Union(union) => {
2322 let mut schema = ScopedSchema::new(parent, dialect);
2323 annotate_with(&mut union.with, &mut schema, dialect);
2324 let columns = annotate_scoped_expression(&mut union.left, Some(&schema), dialect);
2325 annotate_scoped_expression(&mut union.right, Some(&schema), dialect);
2326 columns
2327 }
2328 Expression::Intersect(intersect) => {
2329 let mut schema = ScopedSchema::new(parent, dialect);
2330 annotate_with(&mut intersect.with, &mut schema, dialect);
2331 let columns = annotate_scoped_expression(&mut intersect.left, Some(&schema), dialect);
2332 annotate_scoped_expression(&mut intersect.right, Some(&schema), dialect);
2333 columns
2334 }
2335 Expression::Except(except) => {
2336 let mut schema = ScopedSchema::new(parent, dialect);
2337 annotate_with(&mut except.with, &mut schema, dialect);
2338 let columns = annotate_scoped_expression(&mut except.left, Some(&schema), dialect);
2339 annotate_scoped_expression(&mut except.right, Some(&schema), dialect);
2340 columns
2341 }
2342 _ => {
2343 let mut annotator = TypeAnnotator::new(parent, dialect);
2344 annotator.annotate_in_place(expression);
2345 Vec::new()
2346 }
2347 }
2348}
2349
2350pub fn annotate_types(
2356 expr: &mut Expression,
2357 schema: Option<&dyn Schema>,
2358 dialect: Option<DialectType>,
2359) {
2360 annotate_scoped_expression(expr, schema, dialect);
2361}
2362
2363#[cfg(test)]
2364mod tests {
2365 use super::*;
2366 use crate::expressions::{BooleanLiteral, Cast, ExtractFunc, Null};
2367 use crate::{parse_one, DialectType, MappingSchema, Schema};
2368
2369 fn make_int_literal(val: i64) -> Expression {
2370 Expression::Literal(Box::new(Literal::Number(val.to_string())))
2371 }
2372
2373 fn make_float_literal(val: f64) -> Expression {
2374 Expression::Literal(Box::new(Literal::Number(val.to_string())))
2375 }
2376
2377 fn make_string_literal(val: &str) -> Expression {
2378 Expression::Literal(Box::new(Literal::String(val.to_string())))
2379 }
2380
2381 fn make_bool_literal(val: bool) -> Expression {
2382 Expression::Boolean(BooleanLiteral { value: val })
2383 }
2384
2385 #[test]
2386 fn test_literal_types() {
2387 let mut annotator = TypeAnnotator::new(None, None);
2388
2389 let int_expr = make_int_literal(42);
2391 assert_eq!(
2392 annotator.annotate(&int_expr),
2393 Some(DataType::Int {
2394 length: None,
2395 integer_spelling: false
2396 })
2397 );
2398
2399 let float_expr = make_float_literal(3.14);
2401 assert_eq!(
2402 annotator.annotate(&float_expr),
2403 Some(DataType::Double {
2404 precision: None,
2405 scale: None
2406 })
2407 );
2408
2409 let string_expr = make_string_literal("hello");
2411 assert_eq!(
2412 annotator.annotate(&string_expr),
2413 Some(DataType::VarChar {
2414 length: None,
2415 parenthesized_length: false
2416 })
2417 );
2418
2419 let bool_expr = make_bool_literal(true);
2421 assert_eq!(annotator.annotate(&bool_expr), Some(DataType::Boolean));
2422
2423 let null_expr = Expression::Null(Null);
2425 assert_eq!(annotator.annotate(&null_expr), None);
2426 }
2427
2428 #[test]
2429 fn test_comparison_types() {
2430 let mut annotator = TypeAnnotator::new(None, None);
2431
2432 let cmp = Expression::Gt(Box::new(BinaryOp::new(
2434 make_int_literal(1),
2435 make_int_literal(2),
2436 )));
2437 assert_eq!(annotator.annotate(&cmp), Some(DataType::Boolean));
2438
2439 let eq = Expression::Eq(Box::new(BinaryOp::new(
2441 make_string_literal("a"),
2442 make_string_literal("b"),
2443 )));
2444 assert_eq!(annotator.annotate(&eq), Some(DataType::Boolean));
2445 }
2446
2447 #[test]
2448 fn test_arithmetic_types() {
2449 let mut annotator = TypeAnnotator::new(None, None);
2450
2451 let add_int = Expression::Add(Box::new(BinaryOp::new(
2453 make_int_literal(1),
2454 make_int_literal(2),
2455 )));
2456 assert_eq!(
2457 annotator.annotate(&add_int),
2458 Some(DataType::Int {
2459 length: None,
2460 integer_spelling: false
2461 })
2462 );
2463
2464 let add_mixed = Expression::Add(Box::new(BinaryOp::new(
2466 make_int_literal(1),
2467 make_float_literal(2.5), )));
2469 assert_eq!(
2470 annotator.annotate(&add_mixed),
2471 Some(DataType::Double {
2472 precision: None,
2473 scale: None
2474 })
2475 );
2476 }
2477
2478 #[test]
2479 fn test_string_concat_type() {
2480 let mut annotator = TypeAnnotator::new(None, None);
2481
2482 let concat = Expression::Concat(Box::new(BinaryOp::new(
2484 make_string_literal("hello"),
2485 make_string_literal(" world"),
2486 )));
2487 assert_eq!(
2488 annotator.annotate(&concat),
2489 Some(DataType::VarChar {
2490 length: None,
2491 parenthesized_length: false
2492 })
2493 );
2494 }
2495
2496 #[test]
2497 fn test_cast_type() {
2498 let mut annotator = TypeAnnotator::new(None, None);
2499
2500 let cast = Expression::Cast(Box::new(Cast {
2502 this: make_int_literal(1),
2503 to: DataType::VarChar {
2504 length: Some(10),
2505 parenthesized_length: false,
2506 },
2507 trailing_comments: vec![],
2508 double_colon_syntax: false,
2509 format: None,
2510 default: None,
2511 inferred_type: None,
2512 }));
2513 assert_eq!(
2514 annotator.annotate(&cast),
2515 Some(DataType::VarChar {
2516 length: Some(10),
2517 parenthesized_length: false
2518 })
2519 );
2520 }
2521
2522 #[test]
2523 fn test_function_types() {
2524 let mut annotator = TypeAnnotator::new(None, None);
2525
2526 let count =
2528 Expression::Function(Box::new(Function::new("COUNT", vec![make_int_literal(1)])));
2529 assert_eq!(
2530 annotator.annotate(&count),
2531 Some(DataType::BigInt { length: None })
2532 );
2533
2534 let upper = Expression::Function(Box::new(Function::new(
2536 "UPPER",
2537 vec![make_string_literal("hello")],
2538 )));
2539 assert_eq!(
2540 annotator.annotate(&upper),
2541 Some(DataType::VarChar {
2542 length: None,
2543 parenthesized_length: false
2544 })
2545 );
2546
2547 let now = Expression::Function(Box::new(Function::new("NOW", vec![])));
2549 assert_eq!(
2550 annotator.annotate(&now),
2551 Some(DataType::Timestamp {
2552 precision: None,
2553 timezone: false
2554 })
2555 );
2556 }
2557
2558 #[test]
2559 fn test_duckdb_trim_stores_inferred_types() {
2560 let varchar = DataType::VarChar {
2561 length: None,
2562 parenthesized_length: false,
2563 };
2564 let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
2565 schema
2566 .add_table(
2567 "records",
2568 &[
2569 ("name".to_string(), varchar.clone()),
2570 ("chars".to_string(), varchar.clone()),
2571 ("values_json".to_string(), DataType::Json),
2572 ],
2573 None,
2574 )
2575 .unwrap();
2576
2577 for function in [
2578 "TRIM(name)",
2579 "trim(records.name)",
2580 "TRIM(name, chars)",
2581 "TRIM(BOTH chars FROM name)",
2582 "TRIM(LEADING chars FROM name)",
2583 "TRIM(TRAILING chars FROM name)",
2584 "TRIM(FROM name)",
2585 "TRIM(' hello ')",
2586 "TRIM(NULL)",
2587 r#"TRIM(BOTH '"' FROM values_json->>0)"#,
2588 ] {
2589 let sql = format!("SELECT {function} AS normalized FROM records");
2590 for schema in [None, Some(&schema as &dyn Schema)] {
2591 let mut expression = parse_one(&sql, DialectType::DuckDB).unwrap();
2592 let original_sql = expression.sql_for(DialectType::DuckDB);
2593 annotate_types(&mut expression, schema, Some(DialectType::DuckDB));
2594 let Expression::Select(select) = &expression else {
2595 panic!("Expected SELECT for {sql}");
2596 };
2597 let Expression::Alias(alias) = &select.expressions[0] else {
2598 panic!("Expected alias for {sql}");
2599 };
2600 assert!(matches!(alias.this, Expression::Trim(_)), "{sql}");
2601 assert_eq!(alias.this.inferred_type(), Some(&varchar), "{sql}");
2602 assert_eq!(alias.inferred_type.as_ref(), Some(&varchar), "{sql}");
2603 assert_eq!(expression.sql_for(DialectType::DuckDB), original_sql);
2604 }
2605 }
2606 }
2607
2608 #[test]
2609 fn test_int128_inferred_types_and_widening() {
2610 let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
2611 schema
2612 .add_table(
2613 "measurements",
2614 &[("value".to_string(), DataType::Int128)],
2615 None,
2616 )
2617 .unwrap();
2618 for (projection, expected) in [
2619 ("CAST(value AS HUGEINT)", DataType::Int128),
2620 ("value", DataType::Int128),
2621 ("value + CAST(1 AS BIGINT)", DataType::Int128),
2622 ("CAST(1 AS BIGINT) + value", DataType::Int128),
2623 ("COALESCE(value, CAST(1 AS BIGINT))", DataType::Int128),
2624 ("COALESCE(CAST(1 AS BIGINT), value)", DataType::Int128),
2625 (
2626 "CASE WHEN TRUE THEN value ELSE CAST(1 AS BIGINT) END",
2627 DataType::Int128,
2628 ),
2629 ("SUM(value)", DataType::Int128),
2630 ("SUM(CAST(value AS BIGINT))", DataType::Int128),
2631 (
2632 "MEDIAN(value)",
2633 DataType::Double {
2634 precision: None,
2635 scale: None,
2636 },
2637 ),
2638 (
2639 "CAST(value AS HUGEINT[])",
2640 DataType::Array {
2641 element_type: Box::new(DataType::Int128),
2642 dimension: None,
2643 },
2644 ),
2645 ] {
2646 let sql = format!("SELECT {projection} AS widened FROM measurements");
2647 let mut expression = parse_one(&sql, DialectType::DuckDB).unwrap();
2648 annotate_types(&mut expression, Some(&schema), Some(DialectType::DuckDB));
2649 let Expression::Select(select) = &expression else {
2650 panic!("expected SELECT")
2651 };
2652 let Expression::Alias(alias) = &select.expressions[0] else {
2653 panic!("expected alias")
2654 };
2655 assert_eq!(alias.this.inferred_type(), Some(&expected), "{sql}");
2656 assert_eq!(alias.inferred_type.as_ref(), Some(&expected), "{sql}");
2657 }
2658 assert_eq!(
2659 TypeCoercionClass::from_data_type(&DataType::Int128),
2660 Some(TypeCoercionClass::Numeric)
2661 );
2662 }
2663
2664 #[test]
2665 fn test_duckdb_unsigned_integer_coercion_matrix() {
2666 let signed = ["TINYINT", "SMALLINT", "INT", "BIGINT", "HUGEINT"];
2669 let unsigned = ["UTINYINT", "USMALLINT", "UINTEGER", "UBIGINT", "UHUGEINT"];
2670 let arithmetic = [
2671 ["BIGINT", "BIGINT", "BIGINT", "HUGEINT", "DOUBLE"],
2672 ["SMALLINT", "BIGINT", "BIGINT", "HUGEINT", "DOUBLE"],
2673 ["INT", "INT", "BIGINT", "HUGEINT", "DOUBLE"],
2674 ["BIGINT", "BIGINT", "BIGINT", "HUGEINT", "DOUBLE"],
2675 ["HUGEINT", "HUGEINT", "HUGEINT", "HUGEINT", "DOUBLE"],
2676 ];
2677 let combination = [
2678 ["SMALLINT", "INT", "BIGINT", "HUGEINT", "SMALLINT"],
2679 ["SMALLINT", "INT", "BIGINT", "HUGEINT", "INT"],
2680 ["INT", "INT", "BIGINT", "HUGEINT", "BIGINT"],
2681 ["BIGINT", "BIGINT", "BIGINT", "HUGEINT", "HUGEINT"],
2682 ["HUGEINT", "HUGEINT", "HUGEINT", "HUGEINT", "DOUBLE"],
2683 ];
2684 for (i, s) in signed.iter().enumerate() {
2685 for (j, u) in unsigned.iter().enumerate() {
2686 for (a, b) in [(s, u), (u, s)] {
2687 let a = format!("CAST(1 AS {a})");
2688 let b = format!("CAST(1 AS {b})");
2689 for (sql, expected) in [
2690 (format!("{a} + {b}"), arithmetic[i][j]),
2691 (format!("{a} - {b}"), arithmetic[i][j]),
2692 (format!("{a} * {b}"), arithmetic[i][j]),
2693 (format!("{a} % {b}"), arithmetic[i][j]),
2694 (format!("{a} / {b}"), "DOUBLE"),
2695 (format!("COALESCE({a}, {b})"), combination[i][j]),
2696 (
2697 format!("CASE WHEN TRUE THEN {a} ELSE {b} END"),
2698 combination[i][j],
2699 ),
2700 ] {
2701 let expr = parse_one(&sql, DialectType::DuckDB).unwrap();
2702 let expected =
2703 crate::parse_data_type(expected, DialectType::DuckDB).unwrap();
2704 let mut annotator = TypeAnnotator::new(None, Some(DialectType::DuckDB));
2705 assert_eq!(annotator.annotate(&expr), Some(expected), "{sql}");
2706 }
2707 }
2708 }
2709 }
2710 for (i, a) in unsigned.iter().enumerate() {
2711 for (j, b) in unsigned.iter().enumerate() {
2712 let sql = format!("CAST(1 AS {a}) + CAST(1 AS {b})");
2713 let expr = parse_one(&sql, DialectType::DuckDB).unwrap();
2714 let mut annotator = TypeAnnotator::new(None, Some(DialectType::DuckDB));
2715 assert_eq!(
2716 annotator.annotate(&expr),
2717 Some(crate::parse_data_type(unsigned[i.max(j)], DialectType::DuckDB).unwrap()),
2718 "{sql}"
2719 );
2720 }
2721 }
2722 }
2723
2724 #[test]
2725 fn test_duckdb_sum_return_types() {
2726 for (input, output) in [
2727 ("BOOLEAN", "INT128"),
2728 ("TINYINT", "INT128"),
2729 ("SMALLINT", "INT128"),
2730 ("INT", "INT128"),
2731 ("BIGINT", "INT128"),
2732 ("HUGEINT", "INT128"),
2733 ("UTINYINT", "INT128"),
2734 ("USMALLINT", "INT128"),
2735 ("UINTEGER", "INT128"),
2736 ("UBIGINT", "INT128"),
2737 ("UHUGEINT", "DOUBLE"),
2738 ("FLOAT", "DOUBLE"),
2739 ("DOUBLE", "DOUBLE"),
2740 ("DECIMAL(10,2)", "DECIMAL(38,2)"),
2741 ("DECIMAL", "DECIMAL(38,3)"),
2742 ("DECIMAL(10)", "DECIMAL(38,0)"),
2743 ] {
2744 let input_type = crate::parse_data_type(input, DialectType::DuckDB).unwrap();
2745 let expected = crate::parse_data_type(output, DialectType::DuckDB).unwrap();
2746 let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
2747 schema
2748 .add_table("t", &[("x".to_string(), input_type)], None)
2749 .unwrap();
2750 let cast = parse_one(&format!("CAST(1 AS {input})"), DialectType::DuckDB).unwrap();
2751 let function = Expression::Function(Box::new(Function::new("SUM", vec![cast])));
2752 assert_eq!(
2753 TypeAnnotator::new(None, Some(DialectType::DuckDB)).annotate(&function),
2754 Some(expected.clone()),
2755 "SUM({input}) builder"
2756 );
2757 for arg in ["x".to_string(), format!("CAST(1 AS {input})")] {
2758 for projection in [
2759 format!("SUM({arg})"),
2760 format!("SUM(DISTINCT {arg})"),
2761 format!("SUM({arg}) OVER ()"),
2762 format!("SUM({arg}) FILTER (WHERE TRUE)"),
2763 ] {
2764 let sql = format!("SELECT {projection} AS total FROM t");
2765 let mut expr = parse_one(&sql, DialectType::DuckDB).unwrap();
2766 annotate_types(&mut expr, Some(&schema), Some(DialectType::DuckDB));
2767 let Expression::Select(select) = expr else {
2768 unreachable!()
2769 };
2770 let Expression::Alias(alias) = &select.expressions[0] else {
2771 unreachable!()
2772 };
2773 assert_eq!(alias.inferred_type.as_ref(), Some(&expected), "{sql}");
2774 }
2775 }
2776 }
2777 let expr = parse_one("SUM(x)", DialectType::DuckDB).unwrap();
2778 assert_eq!(
2779 TypeAnnotator::new(None, Some(DialectType::DuckDB)).annotate(&expr),
2780 None
2781 );
2782 for dialect in [
2784 DialectType::Generic,
2785 DialectType::PostgreSQL,
2786 DialectType::MySQL,
2787 DialectType::BigQuery,
2788 ] {
2789 let expr = parse_one("SUM(CAST(1 AS BIGINT))", dialect).unwrap();
2790 assert_eq!(
2791 TypeAnnotator::new(None, Some(dialect)).annotate(&expr),
2792 Some(DataType::BigInt { length: None })
2793 );
2794 }
2795 }
2796
2797 #[test]
2798 fn test_trim_annotates_both_arguments_and_nested_children() {
2799 let varchar = DataType::VarChar {
2800 length: None,
2801 parenthesized_length: false,
2802 };
2803 let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
2804 schema
2805 .add_table(
2806 "users",
2807 &[
2808 ("name".to_string(), varchar.clone()),
2809 ("chars".to_string(), varchar.clone()),
2810 ],
2811 None,
2812 )
2813 .unwrap();
2814
2815 fn check_children(expr: &Expression, varchar: &DataType, has_schema: bool) -> usize {
2816 let mut count = 0;
2817 if matches!(
2818 expr,
2819 Expression::Trim(_)
2820 | Expression::Lower(_)
2821 | Expression::Upper(_)
2822 | Expression::Column(_)
2823 ) {
2824 let expected = if matches!(expr, Expression::Column(_)) && !has_schema {
2825 None
2826 } else {
2827 Some(varchar)
2828 };
2829 assert_eq!(expr.inferred_type(), expected, "{}", expr.sql());
2830 count += 1;
2831 }
2832 crate::ast_children::for_each_child(expr, |_, child| {
2833 count += check_children(child, varchar, has_schema);
2834 });
2835 count
2836 }
2837
2838 for schema in [None, Some(&schema as &dyn Schema)] {
2839 let mut expression = parse_one(
2840 "SELECT TRIM(LOWER(TRIM(name)), UPPER(chars)) AS normalized FROM users",
2841 DialectType::DuckDB,
2842 )
2843 .unwrap();
2844 annotate_types(&mut expression, schema, Some(DialectType::DuckDB));
2845 assert_eq!(check_children(&expression, &varchar, schema.is_some()), 6);
2846 }
2847 }
2848
2849 #[test]
2850 fn test_trim_type_metadata_roundtrip_across_dialects() {
2851 let varchar = DataType::VarChar {
2852 length: None,
2853 parenthesized_length: false,
2854 };
2855 for dialect in [
2856 DialectType::Generic,
2857 DialectType::DuckDB,
2858 DialectType::PostgreSQL,
2859 DialectType::Snowflake,
2860 DialectType::BigQuery,
2861 DialectType::MySQL,
2862 ] {
2863 let expression = parse_one("TRIM(' hello ')", dialect).unwrap();
2864 assert!(matches!(expression, Expression::Trim(_)));
2865 assert_eq!(expression.inferred_type(), None);
2866 let unannotated = serde_json::to_value(&expression).unwrap();
2867 assert!(unannotated["trim"].get("inferred_type").is_none());
2868
2869 let mut restored: Expression = serde_json::from_value(unannotated).unwrap();
2871 assert_eq!(restored, expression);
2872 annotate_types(&mut restored, None, Some(dialect));
2873 assert_eq!(restored.inferred_type(), Some(&varchar), "{dialect:?}");
2874 assert_eq!(restored.sql_for(dialect), expression.sql_for(dialect));
2875
2876 let annotated = serde_json::to_value(&restored).unwrap();
2877 assert_eq!(annotated["trim"]["inferred_type"]["data_type"], "var_char");
2878 let roundtripped: Expression = serde_json::from_value(annotated).unwrap();
2879 assert_eq!(roundtripped, restored);
2880 assert_eq!(roundtripped.inferred_type(), Some(&varchar));
2881 }
2882 }
2883
2884 #[test]
2885 fn test_duckdb_regexp_extract_all_overload_types() {
2886 let varchar = DataType::VarChar {
2887 length: None,
2888 parenthesized_length: false,
2889 };
2890 let captures = DataType::Struct {
2891 fields: vec![
2892 StructField::new("Letter".to_string(), varchar.clone()),
2893 StructField::new("number".to_string(), varchar.clone()),
2894 ],
2895 nested: false,
2896 };
2897 let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
2898 schema
2899 .add_table("documents", &[("body".to_string(), varchar.clone())], None)
2900 .unwrap();
2901
2902 for (arguments, element_type) in [
2903 ("body, '[0-9]+'", &varchar),
2904 ("documents.body, '[0-9]+'", &varchar),
2905 ("'a1b22', '[0-9]+'", &varchar),
2906 ("'abc', '[0-9]+'", &varchar),
2907 ("NULL, '[0-9]+'", &varchar),
2908 ("body, '([a-z])([0-9]+)', 0", &varchar),
2909 ("body, '([a-z])([0-9]+)', 2", &varchar),
2910 ("body, '([a-z])([0-9]+)', (1), 'i'", &varchar),
2911 ("body, '([a-z])([0-9]+)', CAST(1 AS INTEGER)", &varchar),
2912 ("body, '([a-z])([0-9]+)', NULL", &varchar),
2913 ("body, '([a-z])([0-9]+)', ['Letter', 'number']", &captures),
2914 (
2915 "body, '([a-z])([0-9]+)', (['Letter', 'number']), 'i'",
2916 &captures,
2917 ),
2918 (
2919 "body, '([a-z])([0-9]+)', ARRAY['Letter', 'number']",
2920 &captures,
2921 ),
2922 (
2923 "NULL, '([a-z])([0-9]+)', LIST['Letter', 'number']",
2924 &captures,
2925 ),
2926 ] {
2927 let expected = DataType::Array {
2928 element_type: Box::new(element_type.clone()),
2929 dimension: None,
2930 };
2931 for name in ["REGEXP_EXTRACT_ALL", "ReGeXp_ExTrAcT_AlL"] {
2932 for schema in [None, Some(&schema as &dyn Schema)] {
2933 let sql = format!("SELECT {name}({arguments}) AS matches FROM documents");
2934 let mut expression = parse_one(&sql, DialectType::DuckDB).unwrap();
2935 let original_sql = expression.sql_for(DialectType::DuckDB);
2936 annotate_types(&mut expression, schema, Some(DialectType::DuckDB));
2937 let Expression::Select(select) = &expression else {
2938 panic!("Expected SELECT for {sql}");
2939 };
2940 let Expression::Alias(alias) = &select.expressions[0] else {
2941 panic!("Expected alias for {sql}");
2942 };
2943 assert_eq!(alias.this.inferred_type(), Some(&expected), "{sql}");
2944 assert_eq!(alias.inferred_type.as_ref(), Some(&expected), "{sql}");
2945 assert_eq!(expression.sql_for(DialectType::DuckDB), original_sql);
2946 let json = serde_json::to_value(&expression).unwrap();
2947 let restored: Expression = serde_json::from_value(json).unwrap();
2948 assert_eq!(restored, expression);
2949
2950 let sql = format!(
2951 "SELECT UNNEST({name}({arguments})) AS single_match FROM documents"
2952 );
2953 let mut expression = parse_one(&sql, DialectType::DuckDB).unwrap();
2954 annotate_types(&mut expression, schema, Some(DialectType::DuckDB));
2955 let Expression::Select(select) = &expression else {
2956 panic!("Expected SELECT for {sql}");
2957 };
2958 let Expression::Alias(alias) = &select.expressions[0] else {
2959 panic!("Expected alias for {sql}");
2960 };
2961 assert_eq!(alias.this.inferred_type(), Some(element_type), "{sql}");
2962 assert_eq!(alias.inferred_type.as_ref(), Some(element_type), "{sql}");
2963 }
2964 }
2965 }
2966 }
2967
2968 #[test]
2969 fn test_duckdb_regexp_extract_all_unresolved_overloads() {
2970 let varchar = DataType::VarChar {
2971 length: None,
2972 parenthesized_length: false,
2973 };
2974 let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
2975 schema
2976 .add_table(
2977 "documents",
2978 &[(
2979 "names".to_string(),
2980 DataType::Array {
2981 element_type: Box::new(varchar),
2982 dimension: None,
2983 },
2984 )],
2985 None,
2986 )
2987 .unwrap();
2988
2989 for arguments in [
2992 "",
2993 "'a1'",
2994 "'a1', '(a)(1)', 0, 'i', 1",
2995 "'a1', '(a)(1)', missing_group",
2996 "'a1', '(a)(1)', documents.names",
2997 "'a1', '(a)(1)', ['letter', missing_name]",
2998 "'a1', '(a)(1)', CAST(['letter', 'number'] AS VARCHAR[])",
2999 "'a1', '(a)(1)', []",
3000 "'a1', '(a)(1)', [NULL]",
3001 "'a1', '(a)(1)', ['letter', 'LETTER']",
3002 "'a1', '(a)(1)', 1.0",
3003 "'a1', '(a)(1)', CAST(1 AS BIGINT)",
3004 ] {
3005 let sql = format!("REGEXP_EXTRACT_ALL({arguments})");
3006 let mut expression = parse_one(&sql, DialectType::DuckDB).unwrap();
3007 let mut annotator = TypeAnnotator::new(Some(&schema), Some(DialectType::DuckDB));
3008 assert_eq!(annotator.annotate(&expression), None, "{sql}");
3009 annotator.annotate_in_place(&mut expression);
3010 assert_eq!(expression.inferred_type(), None, "{sql}");
3011 }
3012 }
3013
3014 #[test]
3015 fn test_regexp_extract_all_rule_is_duckdb_specific() {
3016 for dialect in [
3019 None,
3020 Some(DialectType::Generic),
3021 Some(DialectType::BigQuery),
3022 Some(DialectType::Snowflake),
3023 Some(DialectType::Databricks),
3024 ] {
3025 for input in [
3026 make_string_literal("a1"),
3027 Expression::Literal(Box::new(Literal::ByteString("a1".to_string()))),
3028 ] {
3029 let mut annotator = TypeAnnotator::new(None, dialect);
3030 let expected = annotator.annotate(&input);
3031 let function = Expression::Function(Box::new(Function::new(
3032 "REGEXP_EXTRACT_ALL",
3033 vec![input, make_string_literal("[0-9]+")],
3034 )));
3035 assert_eq!(annotator.annotate(&function), expected, "{dialect:?}");
3036 }
3037 }
3038 }
3039
3040 #[test]
3041 fn test_duckdb_date_name_types() {
3042 let varchar = DataType::VarChar {
3043 length: None,
3044 parenthesized_length: false,
3045 };
3046 for input_type in [
3047 DataType::Date,
3048 DataType::Timestamp {
3049 precision: None,
3050 timezone: false,
3051 },
3052 DataType::Timestamp {
3053 precision: None,
3054 timezone: true,
3055 },
3056 ] {
3057 let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
3058 schema
3059 .add_table(
3060 "events",
3061 &[("created_at".to_string(), input_type.clone())],
3062 None,
3063 )
3064 .unwrap();
3065 for function in ["MONTHNAME", "MoNtHnAmE", "DAYNAME", "DaYnAmE"] {
3066 for input in [
3067 "created_at",
3068 "events.created_at",
3069 "DATE '2026-01-01'",
3070 "TIMESTAMP '2026-01-01 12:00:00'",
3071 "TIMESTAMPTZ '2026-01-01 12:00:00+00'",
3072 "NULL",
3073 ] {
3074 let sql = format!("SELECT {function}({input}) AS label FROM events");
3075 for schema in [None, Some(&schema as &dyn Schema)] {
3076 let mut expression = parse_one(&sql, DialectType::DuckDB).unwrap();
3077 let original_sql = expression.sql_for(DialectType::DuckDB);
3078 annotate_types(&mut expression, schema, Some(DialectType::DuckDB));
3079 let Expression::Select(select) = &expression else {
3080 panic!("Expected SELECT for {sql}");
3081 };
3082 let Expression::Alias(alias) = &select.expressions[0] else {
3083 panic!("Expected alias for {sql}");
3084 };
3085 assert_eq!(alias.this.inferred_type(), Some(&varchar), "{sql}");
3086 assert_eq!(alias.inferred_type.as_ref(), Some(&varchar), "{sql}");
3087 if let Expression::Function(function) = &alias.this {
3088 if let Expression::Column(column) = &function.args[0] {
3089 assert_eq!(
3090 column.inferred_type.as_ref(),
3091 schema.map(|_| &input_type),
3092 "Argument type must remain unchanged for {sql}"
3093 );
3094 }
3095 }
3096 assert_eq!(expression.sql_for(DialectType::DuckDB), original_sql);
3097 let json = serde_json::to_value(&expression).unwrap();
3098 let restored: Expression = serde_json::from_value(json).unwrap();
3099 assert_eq!(restored, expression);
3100 }
3101 }
3102 }
3103 }
3104 }
3105
3106 #[test]
3107 fn test_date_name_fixed_return_types_are_duckdb_specific() {
3108 for dialect in [
3109 None,
3110 Some(DialectType::Generic),
3111 Some(DialectType::PostgreSQL),
3112 Some(DialectType::MySQL),
3113 Some(DialectType::Snowflake),
3114 ] {
3115 let annotator = TypeAnnotator::new(None, dialect);
3116 for function in ["MONTHNAME", "DAYNAME"] {
3117 assert!(
3118 !annotator.function_return_types.contains_key(function),
3119 "Unexpected fixed return type for {function} in {dialect:?}"
3120 );
3121 }
3122 }
3123 }
3124
3125 #[test]
3126 fn test_duckdb_array_to_string_types() {
3127 let varchar = DataType::VarChar {
3128 length: None,
3129 parenthesized_length: false,
3130 };
3131 let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
3132 schema
3133 .add_table(
3134 "events",
3135 &[
3136 ("label".to_string(), varchar.clone()),
3137 (
3138 "labels".to_string(),
3139 DataType::Array {
3140 element_type: Box::new(varchar.clone()),
3141 dimension: None,
3142 },
3143 ),
3144 ],
3145 None,
3146 )
3147 .unwrap();
3148
3149 for function in [
3150 "ARRAY_TO_STRING",
3151 "array_to_string",
3152 "ArRaY_To_StRiNg_CoMmA_DeFaUlT",
3153 ] {
3154 for input in [
3155 "labels",
3156 "events.labels",
3157 "ARRAY_AGG(label)",
3158 "ARRAY_AGG(events.label)",
3159 "['a', NULL, 'b']",
3160 "[1, 2]",
3161 "[]",
3162 "CAST(NULL AS VARCHAR[])",
3163 "NULL",
3164 ] {
3165 let arguments = if function.eq_ignore_ascii_case("ARRAY_TO_STRING") {
3166 format!("{input}, ', '")
3167 } else {
3168 input.to_string()
3169 };
3170 let sql = format!("SELECT {function}({arguments}) AS label_text FROM events");
3171 for schema in [None, Some(&schema as &dyn Schema)] {
3172 let mut expression = parse_one(&sql, DialectType::DuckDB).unwrap();
3173 annotate_types(&mut expression, schema, Some(DialectType::DuckDB));
3174 let Expression::Select(select) = &expression else {
3175 panic!("Expected SELECT for {sql}");
3176 };
3177 let Expression::Alias(alias) = &select.expressions[0] else {
3178 panic!("Expected alias for {sql}");
3179 };
3180 assert_eq!(alias.this.inferred_type(), Some(&varchar), "{sql}");
3181 assert_eq!(alias.inferred_type.as_ref(), Some(&varchar), "{sql}");
3182 }
3183 }
3184 }
3185 }
3186
3187 #[test]
3188 fn test_array_to_string_fixed_return_types_are_duckdb_specific() {
3189 for dialect in [
3192 None,
3193 Some(DialectType::Generic),
3194 Some(DialectType::BigQuery),
3195 Some(DialectType::PostgreSQL),
3196 Some(DialectType::Snowflake),
3197 ] {
3198 let annotator = TypeAnnotator::new(None, dialect);
3199 for function in ["ARRAY_TO_STRING", "ARRAY_TO_STRING_COMMA_DEFAULT"] {
3200 assert!(
3201 !annotator.function_return_types.contains_key(function),
3202 "Unexpected fixed return type for {function} in {dialect:?}"
3203 );
3204 }
3205 }
3206 }
3207
3208 #[test]
3209 fn test_extract_types_are_dialect_and_field_specific() {
3210 let double = DataType::Double {
3211 precision: None,
3212 scale: None,
3213 };
3214 let bigint = DataType::BigInt { length: None };
3215 let int = DataType::Int {
3216 length: None,
3217 integer_spelling: false,
3218 };
3219
3220 for (field, duckdb_type) in [
3221 (DateTimeField::Year, &bigint),
3222 (DateTimeField::Second, &bigint),
3223 (DateTimeField::Millisecond, &bigint),
3224 (DateTimeField::Microsecond, &bigint),
3225 (DateTimeField::Custom("yearweek".to_string()), &bigint),
3226 (DateTimeField::Epoch, &double),
3227 (DateTimeField::Custom("EpOcH".to_string()), &double),
3228 (DateTimeField::Custom("julian".to_string()), &double),
3229 (DateTimeField::Custom("JuLiAn".to_string()), &double),
3230 ] {
3231 let extract = Expression::Extract(Box::new(ExtractFunc {
3232 this: make_string_literal("2024-02-03 04:05:06.123456"),
3233 field,
3234 }));
3235 for dialect in [
3236 None,
3237 Some(DialectType::Generic),
3238 Some(DialectType::PostgreSQL),
3239 Some(DialectType::Snowflake),
3240 Some(DialectType::DuckDB),
3241 ] {
3242 let expected = if dialect == Some(DialectType::DuckDB) {
3243 duckdb_type
3244 } else {
3245 &int
3246 };
3247 assert_eq!(
3248 TypeAnnotator::new(None, dialect)
3249 .annotate(&extract)
3250 .as_ref(),
3251 Some(expected),
3252 "unexpected type for {extract:?} in {dialect:?}"
3253 );
3254 }
3255 }
3256 }
3257
3258 #[test]
3259 fn test_duckdb_date_trunc_overload_types() {
3260 fn cast_to(data_type: DataType) -> Expression {
3261 Expression::Cast(Box::new(Cast {
3262 this: make_string_literal("value"),
3263 to: data_type,
3264 format: None,
3265 trailing_comments: Vec::new(),
3266 double_colon_syntax: false,
3267 default: None,
3268 inferred_type: None,
3269 }))
3270 }
3271
3272 fn date_trunc(value: Expression) -> Expression {
3273 Expression::Function(Box::new(Function::new(
3274 "DATE_TRUNC",
3275 vec![make_string_literal("month"), value],
3276 )))
3277 }
3278
3279 let mut annotator = TypeAnnotator::new(None, Some(DialectType::DuckDB));
3280
3281 for input_type in [
3282 DataType::Date,
3283 DataType::Timestamp {
3284 precision: Some(9),
3285 timezone: false,
3286 },
3287 ] {
3288 assert_eq!(
3289 annotator.annotate(&date_trunc(cast_to(input_type))),
3290 Some(DataType::Timestamp {
3291 precision: None,
3292 timezone: false,
3293 })
3294 );
3295 }
3296
3297 assert_eq!(
3298 annotator.annotate(&date_trunc(cast_to(DataType::Timestamp {
3299 precision: Some(6),
3300 timezone: true,
3301 }))),
3302 Some(DataType::Timestamp {
3303 precision: None,
3304 timezone: true,
3305 })
3306 );
3307 assert_eq!(
3308 annotator.annotate(&date_trunc(cast_to(DataType::Interval {
3309 unit: Some("DAY".to_string()),
3310 to: Some("SECOND".to_string()),
3311 }))),
3312 Some(DataType::Interval {
3313 unit: None,
3314 to: None,
3315 })
3316 );
3317 assert_eq!(
3318 annotator.annotate(&date_trunc(Expression::Null(Null))),
3319 None
3320 );
3321 }
3322
3323 #[test]
3324 fn test_coalesce_type_inference() {
3325 let mut annotator = TypeAnnotator::new(None, None);
3326
3327 let coalesce = Expression::Function(Box::new(Function::new(
3329 "COALESCE",
3330 vec![Expression::Null(Null), make_int_literal(1)],
3331 )));
3332 assert_eq!(
3333 annotator.annotate(&coalesce),
3334 Some(DataType::Int {
3335 length: None,
3336 integer_spelling: false
3337 })
3338 );
3339
3340 let specialized_coalesce = Expression::Coalesce(Box::new(crate::expressions::VarArgFunc {
3341 expressions: vec![Expression::Null(Null), make_int_literal(1)],
3342 original_name: None,
3343 inferred_type: None,
3344 }));
3345 assert_eq!(
3346 annotator.annotate(&specialized_coalesce),
3347 Some(DataType::Int {
3348 length: None,
3349 integer_spelling: false
3350 })
3351 );
3352 }
3353
3354 #[test]
3355 fn test_type_coercion_class() {
3356 assert_eq!(
3358 TypeCoercionClass::from_data_type(&DataType::VarChar {
3359 length: None,
3360 parenthesized_length: false
3361 }),
3362 Some(TypeCoercionClass::Text)
3363 );
3364 assert_eq!(
3365 TypeCoercionClass::from_data_type(&DataType::Text),
3366 Some(TypeCoercionClass::Text)
3367 );
3368
3369 assert_eq!(
3371 TypeCoercionClass::from_data_type(&DataType::Int {
3372 length: None,
3373 integer_spelling: false
3374 }),
3375 Some(TypeCoercionClass::Numeric)
3376 );
3377 assert_eq!(
3378 TypeCoercionClass::from_data_type(&DataType::Double {
3379 precision: None,
3380 scale: None
3381 }),
3382 Some(TypeCoercionClass::Numeric)
3383 );
3384
3385 assert_eq!(
3387 TypeCoercionClass::from_data_type(&DataType::Date),
3388 Some(TypeCoercionClass::Timelike)
3389 );
3390 assert_eq!(
3391 TypeCoercionClass::from_data_type(&DataType::Timestamp {
3392 precision: None,
3393 timezone: false
3394 }),
3395 Some(TypeCoercionClass::Timelike)
3396 );
3397
3398 assert_eq!(TypeCoercionClass::from_data_type(&DataType::Json), None);
3400 }
3401
3402 #[test]
3403 fn test_wider_numeric_type() {
3404 let annotator = TypeAnnotator::new(None, None);
3405
3406 let result = annotator.wider_numeric_type(
3408 &DataType::Int {
3409 length: None,
3410 integer_spelling: false,
3411 },
3412 &DataType::BigInt { length: None },
3413 );
3414 assert_eq!(result, DataType::BigInt { length: None });
3415
3416 let result = annotator.wider_numeric_type(
3418 &DataType::Float {
3419 precision: None,
3420 scale: None,
3421 real_spelling: false,
3422 },
3423 &DataType::Double {
3424 precision: None,
3425 scale: None,
3426 },
3427 );
3428 assert_eq!(
3429 result,
3430 DataType::Double {
3431 precision: None,
3432 scale: None
3433 }
3434 );
3435
3436 let result = annotator.wider_numeric_type(
3438 &DataType::Int {
3439 length: None,
3440 integer_spelling: false,
3441 },
3442 &DataType::Double {
3443 precision: None,
3444 scale: None,
3445 },
3446 );
3447 assert_eq!(
3448 result,
3449 DataType::Double {
3450 precision: None,
3451 scale: None
3452 }
3453 );
3454 }
3455
3456 #[test]
3457 fn test_aggregate_return_types() {
3458 let mut annotator = TypeAnnotator::new(None, None);
3459
3460 let sum_type = annotator.get_aggregate_return_type("SUM", &[make_int_literal(1)]);
3462 assert_eq!(sum_type, Some(DataType::BigInt { length: None }));
3463
3464 let avg_type = annotator.get_aggregate_return_type("AVG", &[make_int_literal(1)]);
3466 assert_eq!(
3467 avg_type,
3468 Some(DataType::Double {
3469 precision: None,
3470 scale: None
3471 })
3472 );
3473
3474 let min_type = annotator.get_aggregate_return_type("MIN", &[make_string_literal("a")]);
3476 assert_eq!(
3477 min_type,
3478 Some(DataType::VarChar {
3479 length: None,
3480 parenthesized_length: false
3481 })
3482 );
3483
3484 let top_n_type = annotator
3486 .get_aggregate_return_type("MAX", &[make_string_literal("a"), make_int_literal(2)]);
3487 assert_eq!(
3488 top_n_type,
3489 Some(DataType::Array {
3490 element_type: Box::new(DataType::VarChar {
3491 length: None,
3492 parenthesized_length: false,
3493 }),
3494 dimension: None,
3495 })
3496 );
3497 }
3498
3499 #[test]
3500 fn test_date_literal_types() {
3501 let mut annotator = TypeAnnotator::new(None, None);
3502
3503 let date_expr = Expression::Literal(Box::new(Literal::Date("2024-01-15".to_string())));
3505 assert_eq!(annotator.annotate(&date_expr), Some(DataType::Date));
3506
3507 let time_expr = Expression::Literal(Box::new(Literal::Time("10:30:00".to_string())));
3509 assert_eq!(
3510 annotator.annotate(&time_expr),
3511 Some(DataType::Time {
3512 precision: None,
3513 timezone: false
3514 })
3515 );
3516
3517 let ts_expr = Expression::Literal(Box::new(Literal::Timestamp(
3519 "2024-01-15 10:30:00".to_string(),
3520 )));
3521 assert_eq!(
3522 annotator.annotate(&ts_expr),
3523 Some(DataType::Timestamp {
3524 precision: None,
3525 timezone: false
3526 })
3527 );
3528 }
3529
3530 #[test]
3531 fn test_logical_operations() {
3532 let mut annotator = TypeAnnotator::new(None, None);
3533
3534 let and_expr = Expression::And(Box::new(BinaryOp::new(
3536 make_bool_literal(true),
3537 make_bool_literal(false),
3538 )));
3539 assert_eq!(annotator.annotate(&and_expr), Some(DataType::Boolean));
3540
3541 let or_expr = Expression::Or(Box::new(BinaryOp::new(
3543 make_bool_literal(true),
3544 make_bool_literal(false),
3545 )));
3546 assert_eq!(annotator.annotate(&or_expr), Some(DataType::Boolean));
3547
3548 let not_expr = Expression::Not(Box::new(crate::expressions::UnaryOp::new(
3550 make_bool_literal(true),
3551 )));
3552 assert_eq!(annotator.annotate(¬_expr), Some(DataType::Boolean));
3553 }
3554
3555 #[test]
3560 fn test_subscript_array_type() {
3561 let mut annotator = TypeAnnotator::new(None, None);
3562
3563 let arr = Expression::Array(Box::new(crate::expressions::Array {
3565 expressions: vec![make_int_literal(1), make_int_literal(2)],
3566 inferred_type: None,
3567 }));
3568 let subscript = Expression::Subscript(Box::new(crate::expressions::Subscript {
3569 this: arr,
3570 index: make_int_literal(0),
3571 }));
3572 assert_eq!(
3573 annotator.annotate(&subscript),
3574 Some(DataType::Int {
3575 length: None,
3576 integer_spelling: false
3577 })
3578 );
3579 }
3580
3581 #[test]
3582 fn test_subscript_map_type() {
3583 let mut annotator = TypeAnnotator::new(None, None);
3584
3585 let map = Expression::Map(Box::new(crate::expressions::Map {
3587 keys: vec![make_string_literal("a")],
3588 values: vec![make_int_literal(1)],
3589 }));
3590 let subscript = Expression::Subscript(Box::new(crate::expressions::Subscript {
3591 this: map,
3592 index: make_string_literal("a"),
3593 }));
3594 assert_eq!(
3595 annotator.annotate(&subscript),
3596 Some(DataType::Int {
3597 length: None,
3598 integer_spelling: false
3599 })
3600 );
3601 }
3602
3603 #[test]
3604 fn test_struct_type() {
3605 let mut annotator = TypeAnnotator::new(None, None);
3606
3607 let struct_expr = Expression::Struct(Box::new(crate::expressions::Struct {
3609 fields: vec![
3610 (Some("name".to_string()), make_string_literal("Alice")),
3611 (Some("age".to_string()), make_int_literal(30)),
3612 ],
3613 }));
3614 let result = annotator.annotate(&struct_expr);
3615 assert!(matches!(result, Some(DataType::Struct { fields, .. }) if fields.len() == 2));
3616 }
3617
3618 #[test]
3619 fn test_map_type() {
3620 let mut annotator = TypeAnnotator::new(None, None);
3621
3622 let map_expr = Expression::Map(Box::new(crate::expressions::Map {
3624 keys: vec![make_string_literal("a"), make_string_literal("b")],
3625 values: vec![make_int_literal(1), make_int_literal(2)],
3626 }));
3627 let result = annotator.annotate(&map_expr);
3628 assert!(matches!(
3629 result,
3630 Some(DataType::Map { key_type, value_type })
3631 if matches!(*key_type, DataType::VarChar { .. })
3632 && matches!(*value_type, DataType::Int { .. })
3633 ));
3634 }
3635
3636 #[test]
3637 fn test_explode_array_type() {
3638 let mut annotator = TypeAnnotator::new(None, None);
3639
3640 let arr = Expression::Array(Box::new(crate::expressions::Array {
3642 expressions: vec![make_int_literal(1), make_int_literal(2)],
3643 inferred_type: None,
3644 }));
3645 let explode = Expression::Explode(Box::new(crate::expressions::UnaryFunc {
3646 this: arr,
3647 original_name: None,
3648 inferred_type: None,
3649 }));
3650 assert_eq!(
3651 annotator.annotate(&explode),
3652 Some(DataType::Int {
3653 length: None,
3654 integer_spelling: false
3655 })
3656 );
3657 }
3658
3659 #[test]
3660 fn test_unnest_array_type() {
3661 let mut annotator = TypeAnnotator::new(None, None);
3662
3663 let arr = Expression::Array(Box::new(crate::expressions::Array {
3665 expressions: vec![make_string_literal("a"), make_string_literal("b")],
3666 inferred_type: None,
3667 }));
3668 let unnest = Expression::Unnest(Box::new(crate::expressions::UnnestFunc {
3669 this: arr,
3670 expressions: Vec::new(),
3671 with_ordinality: false,
3672 alias: None,
3673 offset_alias: None,
3674 inferred_type: None,
3675 }));
3676 assert_eq!(
3677 annotator.annotate(&unnest),
3678 Some(DataType::VarChar {
3679 length: None,
3680 parenthesized_length: false
3681 })
3682 );
3683 }
3684
3685 #[test]
3686 fn test_annotate_duckdb_array_case_unnest_types() {
3687 let timestamp = DataType::Timestamp {
3688 precision: None,
3689 timezone: false,
3690 };
3691 let array_timestamp = DataType::Array {
3692 element_type: Box::new(timestamp.clone()),
3693 dimension: None,
3694 };
3695 let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
3696 schema
3697 .add_table(
3698 "events",
3699 &[
3700 ("created_at".to_string(), timestamp.clone()),
3701 ("closed_at".to_string(), timestamp.clone()),
3702 ],
3703 None,
3704 )
3705 .unwrap();
3706
3707 let mut expr = parse_one(
3708 "SELECT UNNEST(CASE WHEN closed_at IS NULL THEN ARRAY[created_at] \
3709 ELSE ARRAY[created_at, closed_at] END) AS event_at FROM events",
3710 DialectType::DuckDB,
3711 )
3712 .unwrap();
3713 annotate_types(&mut expr, Some(&schema), Some(DialectType::DuckDB));
3714
3715 let Expression::Select(select) = &expr else {
3716 panic!("expected select");
3717 };
3718 let Expression::Alias(alias) = &select.expressions[0] else {
3719 panic!("expected alias");
3720 };
3721 let Expression::Function(unnest) = &alias.this else {
3722 panic!("expected UNNEST function");
3723 };
3724 assert_eq!(unnest.name, "UNNEST");
3725 let Expression::Case(case) = &unnest.args[0] else {
3726 panic!("expected case");
3727 };
3728 let Expression::ArrayFunc(then_array) = &case.whens[0].1 else {
3729 panic!("expected ARRAY constructor in THEN branch");
3730 };
3731 let Expression::ArrayFunc(else_array) = case.else_.as_ref().expect("expected ELSE") else {
3732 panic!("expected ARRAY constructor in ELSE branch");
3733 };
3734
3735 assert_eq!(then_array.inferred_type.as_ref(), Some(&array_timestamp));
3736 assert_eq!(else_array.inferred_type.as_ref(), Some(&array_timestamp));
3737 assert_eq!(case.inferred_type.as_ref(), Some(&array_timestamp));
3738 assert_eq!(unnest.inferred_type.as_ref(), Some(×tamp));
3739 assert_eq!(alias.inferred_type.as_ref(), Some(×tamp));
3740 assert!(then_array
3741 .expressions
3742 .iter()
3743 .all(|expression| { expression.inferred_type() == Some(×tamp) }));
3744 assert!(else_array
3745 .expressions
3746 .iter()
3747 .all(|expression| { expression.inferred_type() == Some(×tamp) }));
3748 }
3749
3750 #[test]
3751 fn test_array_and_case_coerce_all_result_types() {
3752 let mut expr = parse_one(
3753 "SELECT CASE WHEN TRUE THEN ARRAY[1] ELSE ARRAY[2.5] END AS values",
3754 DialectType::DuckDB,
3755 )
3756 .unwrap();
3757 annotate_types(&mut expr, None, Some(DialectType::DuckDB));
3758
3759 let Expression::Select(select) = &expr else {
3760 panic!("expected select");
3761 };
3762 let Expression::Alias(alias) = &select.expressions[0] else {
3763 panic!("expected alias");
3764 };
3765 assert_eq!(
3766 alias.this.inferred_type(),
3767 Some(&DataType::Array {
3768 element_type: Box::new(DataType::Double {
3769 precision: None,
3770 scale: None,
3771 }),
3772 dimension: None,
3773 })
3774 );
3775 }
3776
3777 #[test]
3778 fn test_transparent_wrappers_preserve_scalar_types() {
3779 let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
3780 schema
3781 .add_table("flags", &[("flag".to_string(), DataType::Boolean)], None)
3782 .unwrap();
3783 let varchar = DataType::VarChar {
3784 length: None,
3785 parenthesized_length: false,
3786 };
3787
3788 let mut parenthesized = parse_one(
3789 "SELECT (CASE WHEN flag THEN 'yes' ELSE 'no' END) AS label FROM flags",
3790 DialectType::DuckDB,
3791 )
3792 .unwrap();
3793 annotate_types(&mut parenthesized, Some(&schema), Some(DialectType::DuckDB));
3794
3795 let Expression::Select(select) = &parenthesized else {
3796 panic!("expected select");
3797 };
3798 let Expression::Alias(alias) = &select.expressions[0] else {
3799 panic!("expected alias");
3800 };
3801 let Expression::Paren(paren) = &alias.this else {
3802 panic!("expected parenthesized expression");
3803 };
3804 let Expression::Case(case) = &paren.this else {
3805 panic!("expected case");
3806 };
3807 let Expression::Column(column) = &case.whens[0].0 else {
3808 panic!("expected column condition");
3809 };
3810
3811 assert_eq!(alias.this.inferred_type(), Some(&varchar));
3812 assert_eq!(case.inferred_type.as_ref(), Some(&varchar));
3813 assert_eq!(column.inferred_type.as_ref(), Some(&DataType::Boolean));
3814 assert_eq!(alias.inferred_type.as_ref(), Some(&varchar));
3815
3816 let mut annotated = parse_one(
3817 "SELECT CASE WHEN flag THEN 'yes' ELSE 'no' END /*tail*/ FROM flags",
3818 DialectType::DuckDB,
3819 )
3820 .unwrap();
3821 annotate_types(&mut annotated, Some(&schema), Some(DialectType::DuckDB));
3822
3823 let Expression::Select(select) = &annotated else {
3824 panic!("expected select");
3825 };
3826 let Expression::Annotated(annotated) = &select.expressions[0] else {
3827 panic!("expected comment annotation wrapper");
3828 };
3829 let Expression::Case(case) = &annotated.this else {
3830 panic!("expected case");
3831 };
3832 let Expression::Column(column) = &case.whens[0].0 else {
3833 panic!("expected column condition");
3834 };
3835
3836 assert_eq!(select.expressions[0].inferred_type(), Some(&varchar));
3837 assert_eq!(case.inferred_type.as_ref(), Some(&varchar));
3838 assert_eq!(column.inferred_type.as_ref(), Some(&DataType::Boolean));
3839 }
3840
3841 #[test]
3842 fn test_set_operation_type() {
3843 let mut annotator = TypeAnnotator::new(None, None);
3844
3845 let select = Expression::Select(Box::new(crate::expressions::Select::default()));
3847 let union = Expression::Union(Box::new(crate::expressions::Union {
3848 left: select.clone(),
3849 right: select.clone(),
3850 all: false,
3851 distinct: false,
3852 with: None,
3853 order_by: None,
3854 limit: None,
3855 offset: None,
3856 by_name: false,
3857 side: None,
3858 kind: None,
3859 corresponding: false,
3860 strict: false,
3861 on_columns: Vec::new(),
3862 distribute_by: None,
3863 sort_by: None,
3864 cluster_by: None,
3865 }));
3866 assert_eq!(annotator.annotate(&union), None);
3867 }
3868
3869 #[test]
3870 fn test_floor_ceil_input_dependent_types() {
3871 use crate::expressions::{CeilFunc, FloorFunc};
3872
3873 let mut annotator = TypeAnnotator::new(None, None);
3874
3875 let floor_int = Expression::Floor(Box::new(FloorFunc {
3877 this: make_int_literal(42),
3878 scale: None,
3879 to: None,
3880 }));
3881 assert_eq!(
3882 annotator.annotate(&floor_int),
3883 Some(DataType::Double {
3884 precision: None,
3885 scale: None,
3886 })
3887 );
3888
3889 let ceil_int = Expression::Ceil(Box::new(CeilFunc {
3890 this: make_int_literal(42),
3891 decimals: None,
3892 to: None,
3893 }));
3894 assert_eq!(
3895 annotator.annotate(&ceil_int),
3896 Some(DataType::Double {
3897 precision: None,
3898 scale: None,
3899 })
3900 );
3901
3902 let floor_float = Expression::Floor(Box::new(FloorFunc {
3904 this: make_float_literal(3.14),
3905 scale: None,
3906 to: None,
3907 }));
3908 assert_eq!(
3909 annotator.annotate(&floor_float),
3910 Some(DataType::Double {
3911 precision: None,
3912 scale: None,
3913 })
3914 );
3915
3916 let floor_fn =
3918 Expression::Function(Box::new(Function::new("FLOOR", vec![make_int_literal(1)])));
3919 assert_eq!(
3920 annotator.annotate(&floor_fn),
3921 Some(DataType::Int {
3922 length: None,
3923 integer_spelling: false,
3924 })
3925 );
3926 }
3927
3928 #[test]
3929 fn test_sign_preserves_input_type() {
3930 use crate::expressions::UnaryFunc;
3931
3932 let mut annotator = TypeAnnotator::new(None, None);
3933
3934 let sign_int = Expression::Sign(Box::new(UnaryFunc {
3936 this: make_int_literal(42),
3937 original_name: None,
3938 inferred_type: None,
3939 }));
3940 assert_eq!(
3941 annotator.annotate(&sign_int),
3942 Some(DataType::Int {
3943 length: None,
3944 integer_spelling: false,
3945 })
3946 );
3947
3948 let sign_float = Expression::Sign(Box::new(UnaryFunc {
3950 this: make_float_literal(3.14),
3951 original_name: None,
3952 inferred_type: None,
3953 }));
3954 assert_eq!(
3955 annotator.annotate(&sign_float),
3956 Some(DataType::Double {
3957 precision: None,
3958 scale: None,
3959 })
3960 );
3961
3962 let sign_cast = Expression::Sign(Box::new(UnaryFunc {
3964 this: Expression::Cast(Box::new(Cast {
3965 this: make_int_literal(42),
3966 to: DataType::Int {
3967 length: None,
3968 integer_spelling: false,
3969 },
3970 format: None,
3971 trailing_comments: Vec::new(),
3972 double_colon_syntax: false,
3973 default: None,
3974 inferred_type: None,
3975 })),
3976 original_name: None,
3977 inferred_type: None,
3978 }));
3979 assert_eq!(
3980 annotator.annotate(&sign_cast),
3981 Some(DataType::Int {
3982 length: None,
3983 integer_spelling: false,
3984 })
3985 );
3986 }
3987
3988 #[test]
3989 fn test_date_format_types() {
3990 use crate::expressions::{DateFormatFunc, TimeToStr};
3991
3992 let mut annotator = TypeAnnotator::new(None, None);
3993
3994 let date_fmt = Expression::DateFormat(Box::new(DateFormatFunc {
3996 this: make_string_literal("2024-01-01"),
3997 format: make_string_literal("%Y-%m-%d"),
3998 }));
3999 assert_eq!(
4000 annotator.annotate(&date_fmt),
4001 Some(DataType::VarChar {
4002 length: None,
4003 parenthesized_length: false,
4004 })
4005 );
4006
4007 let format_date = Expression::FormatDate(Box::new(DateFormatFunc {
4009 this: make_string_literal("2024-01-01"),
4010 format: make_string_literal("%Y-%m-%d"),
4011 }));
4012 assert_eq!(
4013 annotator.annotate(&format_date),
4014 Some(DataType::VarChar {
4015 length: None,
4016 parenthesized_length: false,
4017 })
4018 );
4019
4020 let time_to_str = Expression::TimeToStr(Box::new(TimeToStr {
4022 this: Box::new(make_string_literal("2024-01-01")),
4023 format: "%Y-%m-%d".to_string(),
4024 culture: None,
4025 zone: None,
4026 }));
4027 assert_eq!(
4028 annotator.annotate(&time_to_str),
4029 Some(DataType::VarChar {
4030 length: None,
4031 parenthesized_length: false,
4032 })
4033 );
4034
4035 let date_fmt_fn = Expression::Function(Box::new(Function::new(
4037 "DATE_FORMAT",
4038 vec![
4039 make_string_literal("2024-01-01"),
4040 make_string_literal("%Y-%m-%d"),
4041 ],
4042 )));
4043 assert_eq!(
4044 annotator.annotate(&date_fmt_fn),
4045 Some(DataType::VarChar {
4046 length: None,
4047 parenthesized_length: false,
4048 })
4049 );
4050 }
4051
4052 #[test]
4055 fn test_annotate_in_place_sets_type_on_root() {
4056 let mut expr = Expression::Add(Box::new(BinaryOp::new(
4058 make_int_literal(1),
4059 make_int_literal(2),
4060 )));
4061 annotate_types(&mut expr, None, None);
4062 assert_eq!(
4063 expr.inferred_type(),
4064 Some(&DataType::Int {
4065 length: None,
4066 integer_spelling: false,
4067 })
4068 );
4069 }
4070
4071 #[test]
4072 fn test_annotate_in_place_sets_types_on_children() {
4073 let inner_add = Expression::Add(Box::new(BinaryOp::new(
4076 make_int_literal(1),
4077 make_float_literal(2.5),
4078 )));
4079 let inner_sub = Expression::Sub(Box::new(BinaryOp::new(
4080 make_int_literal(3),
4081 make_int_literal(4),
4082 )));
4083 let mut expr = Expression::Add(Box::new(BinaryOp::new(inner_add, inner_sub)));
4084 annotate_types(&mut expr, None, None);
4085
4086 assert_eq!(
4088 expr.inferred_type(),
4089 Some(&DataType::Double {
4090 precision: None,
4091 scale: None,
4092 })
4093 );
4094
4095 if let Expression::Add(op) = &expr {
4097 assert_eq!(
4099 op.left.inferred_type(),
4100 Some(&DataType::Double {
4101 precision: None,
4102 scale: None,
4103 })
4104 );
4105 assert_eq!(
4107 op.right.inferred_type(),
4108 Some(&DataType::Int {
4109 length: None,
4110 integer_spelling: false,
4111 })
4112 );
4113 } else {
4114 panic!("Expected Add expression");
4115 }
4116 }
4117
4118 #[test]
4119 fn test_annotate_in_place_comparison() {
4120 let mut expr = Expression::Eq(Box::new(BinaryOp::new(
4121 make_int_literal(1),
4122 make_int_literal(2),
4123 )));
4124 annotate_types(&mut expr, None, None);
4125 assert_eq!(expr.inferred_type(), Some(&DataType::Boolean));
4126 }
4127
4128 #[test]
4129 fn test_annotate_in_place_cast() {
4130 let mut expr = Expression::Cast(Box::new(Cast {
4131 this: make_int_literal(42),
4132 to: DataType::VarChar {
4133 length: None,
4134 parenthesized_length: false,
4135 },
4136 trailing_comments: vec![],
4137 double_colon_syntax: false,
4138 format: None,
4139 default: None,
4140 inferred_type: None,
4141 }));
4142 annotate_types(&mut expr, None, None);
4143 assert_eq!(
4144 expr.inferred_type(),
4145 Some(&DataType::VarChar {
4146 length: None,
4147 parenthesized_length: false,
4148 })
4149 );
4150 }
4151
4152 #[test]
4153 fn test_annotate_in_place_nested_expression() {
4154 let add = Expression::Add(Box::new(BinaryOp::new(
4156 make_int_literal(1),
4157 make_int_literal(2),
4158 )));
4159 let mut expr = Expression::Gt(Box::new(BinaryOp::new(add, make_int_literal(0))));
4160 annotate_types(&mut expr, None, None);
4161
4162 assert_eq!(expr.inferred_type(), Some(&DataType::Boolean));
4163
4164 if let Expression::Gt(op) = &expr {
4166 assert_eq!(
4167 op.left.inferred_type(),
4168 Some(&DataType::Int {
4169 length: None,
4170 integer_spelling: false,
4171 })
4172 );
4173 }
4174 }
4175
4176 #[test]
4177 fn test_annotate_in_place_parsed_sql() {
4178 use crate::parser::Parser;
4179 let mut expr =
4180 Parser::parse_sql("SELECT 1 + 2.0, 'hello', TRUE").expect("parse failed")[0].clone();
4181 annotate_types(&mut expr, None, None);
4182
4183 assert!(expr.inferred_type().is_none());
4187 }
4188
4189 #[test]
4190 fn test_inferred_type_json_roundtrip() {
4191 let mut expr = Expression::Add(Box::new(BinaryOp::new(
4192 make_int_literal(1),
4193 make_int_literal(2),
4194 )));
4195 annotate_types(&mut expr, None, None);
4196
4197 let json = serde_json::to_string(&expr).expect("serialize failed");
4199 assert!(json.contains("inferred_type"));
4201
4202 let deserialized: Expression = serde_json::from_str(&json).expect("deserialize failed");
4204 assert_eq!(
4205 deserialized.inferred_type(),
4206 Some(&DataType::Int {
4207 length: None,
4208 integer_spelling: false,
4209 })
4210 );
4211 }
4212
4213 #[test]
4214 fn test_inferred_type_none_not_serialized() {
4215 let expr = Expression::Add(Box::new(BinaryOp::new(
4217 make_int_literal(1),
4218 make_int_literal(2),
4219 )));
4220 let json = serde_json::to_string(&expr).expect("serialize failed");
4221 assert!(!json.contains("inferred_type"));
4222 }
4223
4224 #[test]
4225 fn test_annotate_if_func_bigquery_node_and_alias_type() {
4226 let mut schema = MappingSchema::with_dialect(DialectType::BigQuery);
4227 schema
4228 .add_table(
4229 "t",
4230 &[("col1".to_string(), DataType::String { length: None })],
4231 None,
4232 )
4233 .unwrap();
4234
4235 let mut expr = parse_one(
4236 "SELECT IF(col1 IS NOT NULL, 1, 0) AS x FROM t",
4237 DialectType::BigQuery,
4238 )
4239 .unwrap();
4240 annotate_types(&mut expr, Some(&schema), Some(DialectType::BigQuery));
4241
4242 let Expression::Select(select) = &expr else {
4243 panic!("expected select");
4244 };
4245 let Expression::Alias(alias) = &select.expressions[0] else {
4246 panic!("expected alias");
4247 };
4248
4249 assert_eq!(
4250 alias.this.inferred_type(),
4251 Some(&DataType::Int {
4252 length: None,
4253 integer_spelling: false,
4254 })
4255 );
4256 assert_eq!(
4257 select.expressions[0].inferred_type(),
4258 Some(&DataType::Int {
4259 length: None,
4260 integer_spelling: false,
4261 })
4262 );
4263 }
4264
4265 #[test]
4266 fn test_annotate_nvl2_node_type() {
4267 let mut expr = parse_one("SELECT NVL2(a, 1, 0) AS x", DialectType::Generic).unwrap();
4268 annotate_types(&mut expr, None, None);
4269
4270 let Expression::Select(select) = &expr else {
4271 panic!("expected select");
4272 };
4273 let Expression::Alias(alias) = &select.expressions[0] else {
4274 panic!("expected alias");
4275 };
4276
4277 assert_eq!(
4278 alias.this.inferred_type(),
4279 Some(&DataType::Int {
4280 length: None,
4281 integer_spelling: false,
4282 })
4283 );
4284 }
4285
4286 #[test]
4287 fn test_annotate_count_node_type() {
4288 let mut expr = parse_one("SELECT COUNT(1) AS x", DialectType::Generic).unwrap();
4289 annotate_types(&mut expr, None, None);
4290
4291 let Expression::Select(select) = &expr else {
4292 panic!("expected select");
4293 };
4294 let Expression::Alias(alias) = &select.expressions[0] else {
4295 panic!("expected alias");
4296 };
4297
4298 assert_eq!(
4299 alias.this.inferred_type(),
4300 Some(&DataType::BigInt { length: None })
4301 );
4302 }
4303
4304 #[test]
4305 fn test_annotate_group_concat_node_type() {
4306 let mut expr = parse_one("SELECT GROUP_CONCAT(a) AS x", DialectType::Generic).unwrap();
4307 annotate_types(&mut expr, None, None);
4308
4309 let Expression::Select(select) = &expr else {
4310 panic!("expected select");
4311 };
4312 let Expression::Alias(alias) = &select.expressions[0] else {
4313 panic!("expected alias");
4314 };
4315
4316 assert_eq!(
4317 alias.this.inferred_type(),
4318 Some(&DataType::VarChar {
4319 length: None,
4320 parenthesized_length: false,
4321 })
4322 );
4323 }
4324
4325 #[test]
4326 fn test_annotate_sum_if_generic_aggregate_type() {
4327 let mut expr =
4328 parse_one("SELECT SUM_IF(1, a > 0) AS x FROM t", DialectType::Generic).unwrap();
4329 annotate_types(&mut expr, None, None);
4330
4331 let Expression::Select(select) = &expr else {
4332 panic!("expected select");
4333 };
4334 let Expression::Alias(alias) = &select.expressions[0] else {
4335 panic!("expected alias");
4336 };
4337
4338 assert_eq!(
4339 select.expressions[0].inferred_type(),
4340 Some(&DataType::BigInt { length: None })
4341 );
4342 assert_eq!(
4343 alias.this.inferred_type(),
4344 Some(&DataType::BigInt { length: None })
4345 );
4346 }
4347
4348 #[test]
4349 fn test_annotate_duckdb_median_node_types() {
4350 let cases = [
4351 (
4352 "SELECT MEDIAN(CAST(1 AS INTEGER)) AS result",
4353 DataType::Double {
4354 precision: None,
4355 scale: None,
4356 },
4357 ),
4358 (
4359 "SELECT MEDIAN(CAST(1 AS FLOAT)) AS result",
4360 DataType::Float {
4361 precision: None,
4362 scale: None,
4363 real_spelling: false,
4364 },
4365 ),
4366 (
4367 "SELECT MEDIAN(CAST(1 AS DECIMAL(10, 2))) AS result",
4368 DataType::Decimal {
4369 precision: Some(10),
4370 scale: Some(2),
4371 },
4372 ),
4373 (
4374 "SELECT MEDIAN(CAST('2024-01-01' AS DATE)) AS result",
4375 DataType::Timestamp {
4376 precision: None,
4377 timezone: false,
4378 },
4379 ),
4380 ];
4381
4382 for (sql, expected) in cases {
4383 let mut expr = parse_one(sql, DialectType::DuckDB).unwrap();
4384 annotate_types(&mut expr, None, Some(DialectType::DuckDB));
4385
4386 let Expression::Select(select) = &expr else {
4387 panic!("expected select for {sql}");
4388 };
4389 let Expression::Alias(alias) = &select.expressions[0] else {
4390 panic!("expected alias for {sql}");
4391 };
4392
4393 assert_eq!(alias.this.inferred_type(), Some(&expected), "{sql}");
4394 assert_eq!(
4395 select.expressions[0].inferred_type(),
4396 Some(&expected),
4397 "{sql}"
4398 );
4399 }
4400 }
4401}