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