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