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