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 let recursive = with.recursive
2486 || matches!(
2487 dialect,
2488 Some(
2489 DialectType::Snowflake
2490 | DialectType::TSQL
2491 | DialectType::Oracle
2492 | DialectType::SQLite
2493 )
2494 );
2495 for cte in &mut with.ctes {
2496 let name = crate::binding::identifier_name(&cte.alias);
2497 let recursive_anchor = if !recursive {
2501 None
2502 } else if let Expression::Union(union) = &mut cte.this {
2503 let references_self = union.right.contains(|node| matches!(node,
2504 Expression::Table(table) if table.schema.is_none() && table.catalog.is_none()
2505 && normalize_name(&crate::binding::identifier_name(&table.name), dialect, false, true)
2506 == normalize_name(&name, dialect, false, true)));
2507 if references_self {
2508 let columns = annotate_scoped_expression_with_outer(
2509 &mut union.left,
2510 Some(schema),
2511 dialect,
2512 outer,
2513 );
2514 let columns = apply_column_aliases(columns, &cte.columns);
2515 let _ = schema.add_table(&name, &columns, dialect);
2516 Some(columns)
2517 } else {
2518 None
2519 }
2520 } else {
2521 None
2522 };
2523 let mut columns =
2524 annotate_scoped_expression_with_outer(&mut cte.this, Some(schema), dialect, outer);
2525 if let Some(anchor) = recursive_anchor {
2526 for ((_, result), (_, initial)) in columns.iter_mut().zip(anchor) {
2527 if *result != initial {
2528 *result = DataType::Unknown;
2529 }
2530 }
2531 }
2532 let columns = apply_column_aliases(columns, &cte.columns);
2533 let _ = schema.add_table(
2534 &crate::binding::identifier_name(&cte.alias),
2535 &columns,
2536 dialect,
2537 );
2538 }
2539 }
2540}
2541
2542fn annotate_select(
2543 select: &mut crate::expressions::Select,
2544 parent: Option<&dyn Schema>,
2545 dialect: Option<DialectType>,
2546 outer: Option<&dyn Schema>,
2547) -> OutputColumns {
2548 let mut ctes = ScopedSchema::new(parent, dialect);
2549 annotate_with(&mut select.with, &mut ctes, dialect, outer);
2550 let mut schema = ScopedSchema::new(Some(&ctes), dialect);
2551 schema.outer = outer;
2552
2553 if let Some(from) = &mut select.from {
2554 for source in &mut from.expressions {
2555 annotate_relation_source(source, &mut schema, dialect);
2556 }
2557 }
2558 for join in &mut select.joins {
2559 annotate_relation_source(&mut join.this, &mut schema, dialect);
2560 }
2561
2562 schema.lookup_parent_columns = false;
2563 let mut annotator = TypeAnnotator::new(Some(&schema), dialect);
2564 annotator.query_schema = Some(&ctes);
2565 for expression in &mut select.expressions {
2566 annotator.annotate_in_place(expression);
2567 }
2568 if let Some(expression) = &mut select.prewhere {
2570 annotator.annotate_in_place(expression);
2571 }
2572 if let Some(clause) = &mut select.qualify {
2573 annotator.annotate_in_place(&mut clause.this);
2574 }
2575 if let Some(clause) = &mut select.where_clause {
2576 annotator.annotate_in_place(&mut clause.this);
2577 }
2578 if let Some(clause) = &mut select.having {
2579 annotator.annotate_in_place(&mut clause.this);
2580 }
2581 if let Some(group) = &mut select.group_by {
2582 for expression in &mut group.expressions {
2583 annotator.annotate_in_place(expression);
2584 }
2585 }
2586 if let Some(order) = &mut select.order_by {
2587 for expression in &mut order.expressions {
2588 annotator.annotate_in_place(&mut expression.this);
2589 }
2590 }
2591 for join in &mut select.joins {
2592 if let Some(on) = &mut join.on {
2593 annotator.annotate_in_place(on);
2594 }
2595 if let Some(condition) = &mut join.match_condition {
2596 annotator.annotate_in_place(condition);
2597 }
2598 }
2599 query_outputs(&select.expressions, dialect)
2600}
2601
2602fn annotate_scoped_expression(
2603 expression: &mut Expression,
2604 parent: Option<&dyn Schema>,
2605 dialect: Option<DialectType>,
2606) -> OutputColumns {
2607 annotate_scoped_expression_with_outer(expression, parent, dialect, None)
2608}
2609
2610fn annotate_scoped_expression_with_outer(
2611 expression: &mut Expression,
2612 parent: Option<&dyn Schema>,
2613 dialect: Option<DialectType>,
2614 outer: Option<&dyn Schema>,
2615) -> OutputColumns {
2616 match expression {
2617 Expression::Select(select) => annotate_select(select, parent, dialect, outer),
2618 Expression::Subquery(subquery) => {
2619 let columns =
2620 annotate_scoped_expression_with_outer(&mut subquery.this, parent, dialect, outer);
2621 if let Some((_, first_type)) = columns.first() {
2622 subquery.inferred_type = Some(first_type.clone());
2623 }
2624 columns
2625 }
2626 Expression::Cte(cte) => {
2627 annotate_scoped_expression_with_outer(&mut cte.this, parent, dialect, outer)
2628 }
2629 Expression::Paren(paren) => {
2630 annotate_scoped_expression_with_outer(&mut paren.this, parent, dialect, outer)
2631 }
2632 Expression::Union(union) => {
2633 let mut schema = ScopedSchema::new(parent, dialect);
2634 annotate_with(&mut union.with, &mut schema, dialect, outer);
2635 annotate_scoped_expression_with_outer(&mut union.left, Some(&schema), dialect, outer);
2636 annotate_scoped_expression_with_outer(&mut union.right, Some(&schema), dialect, outer);
2637 super::set_operation_types::query_columns(expression, dialect)
2638 }
2639 Expression::Intersect(intersect) => {
2640 let mut schema = ScopedSchema::new(parent, dialect);
2641 annotate_with(&mut intersect.with, &mut schema, dialect, outer);
2642 annotate_scoped_expression_with_outer(
2643 &mut intersect.left,
2644 Some(&schema),
2645 dialect,
2646 outer,
2647 );
2648 annotate_scoped_expression_with_outer(
2649 &mut intersect.right,
2650 Some(&schema),
2651 dialect,
2652 outer,
2653 );
2654 super::set_operation_types::query_columns(expression, dialect)
2655 }
2656 Expression::Except(except) => {
2657 let mut schema = ScopedSchema::new(parent, dialect);
2658 annotate_with(&mut except.with, &mut schema, dialect, outer);
2659 annotate_scoped_expression_with_outer(&mut except.left, Some(&schema), dialect, outer);
2660 annotate_scoped_expression_with_outer(&mut except.right, Some(&schema), dialect, outer);
2661 super::set_operation_types::query_columns(expression, dialect)
2662 }
2663 _ => {
2664 if let Some(mut selected) = crate::binding::dml_scope(expression) {
2665 let mut ctes = ScopedSchema::new(parent, dialect);
2666 annotate_with(&mut selected.with, &mut ctes, dialect, outer);
2667 let mut inputs = ScopedSchema::new(Some(&ctes), dialect);
2668 inputs.outer = outer;
2669 if let Some(from) = &mut selected.from {
2670 for source in &mut from.expressions {
2671 annotate_relation_source(source, &mut inputs, dialect);
2672 }
2673 }
2674 for join in &mut selected.joins {
2675 annotate_relation_source(&mut join.this, &mut inputs, dialect);
2676 }
2677 inputs.lookup_parent_columns = false;
2678 let mut annotator = TypeAnnotator::new(Some(&inputs), dialect);
2679 annotator.query_schema = Some(&ctes);
2680 crate::ast_children::for_each_child_mut(expression, |child| {
2681 annotator.annotate_in_place(child)
2682 });
2683 return Vec::new();
2684 }
2685 let mut annotator = TypeAnnotator::new(parent, dialect);
2686 annotator.annotate_in_place(expression);
2687 Vec::new()
2688 }
2689 }
2690}
2691
2692pub fn annotate_types(
2698 expr: &mut Expression,
2699 schema: Option<&dyn Schema>,
2700 dialect: Option<DialectType>,
2701) {
2702 annotate_scoped_expression(expr, schema, dialect);
2703}
2704
2705#[cfg(test)]
2706mod tests {
2707 use super::*;
2708 use crate::expressions::{BooleanLiteral, Cast, ExtractFunc, Null};
2709 use crate::{parse_one, DialectType, MappingSchema, Schema};
2710
2711 #[test]
2712 fn set_operation_types_cover_all_dialects_454() {
2713 use DialectType::*;
2714 for dialect in [
2717 Generic,
2718 PostgreSQL,
2719 MySQL,
2720 BigQuery,
2721 Snowflake,
2722 DuckDB,
2723 SQLite,
2724 Hive,
2725 Spark,
2726 Trino,
2727 Presto,
2728 Redshift,
2729 TSQL,
2730 Oracle,
2731 ClickHouse,
2732 Databricks,
2733 Athena,
2734 Teradata,
2735 Doris,
2736 StarRocks,
2737 Materialize,
2738 RisingWave,
2739 SingleStore,
2740 CockroachDB,
2741 TiDB,
2742 Druid,
2743 Solr,
2744 Tableau,
2745 Dune,
2746 Fabric,
2747 Drill,
2748 Dremio,
2749 Exasol,
2750 DataFusion,
2751 ] {
2752 for (left, right) in [("INT", "BIGINT"), ("BIGINT", "INT")] {
2753 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");
2754 let mut expression = parse_one(&sql, dialect).unwrap();
2755 annotate_types(&mut expression, None, Some(dialect));
2756 let Expression::Select(select) = expression else {
2757 panic!("select")
2758 };
2759 let actual = select.expressions[0].inferred_type();
2760 match dialect {
2761 BigQuery => assert!(
2762 matches!(actual, Some(DataType::Custom { name }) if name == "INT64"),
2763 "{dialect:?}: {actual:?}"
2764 ),
2765 SQLite => assert!(
2766 actual.is_none_or(|t| *t == DataType::Unknown),
2767 "{dialect:?}: {actual:?}"
2768 ),
2769 Teradata if left == "INT" => assert!(
2770 matches!(actual, Some(DataType::Int { .. })),
2771 "{dialect:?}: {actual:?}"
2772 ),
2773 Oracle => assert!(
2774 matches!(
2775 actual,
2776 Some(DataType::Oracle {
2777 oracle_type: crate::expressions::OracleDataType::Number { .. }
2778 })
2779 ),
2780 "{dialect:?}: {actual:?}"
2781 ),
2782 _ => assert!(
2783 matches!(actual, Some(DataType::BigInt { .. })),
2784 "{dialect:?}: {actual:?}"
2785 ),
2786 }
2787 }
2788 let mut expression = parse_one(
2789 "SELECT t.a FROM (SELECT CAST(1 AS DECIMAL(10,2)) AS a UNION ALL SELECT missing_function() AS a) AS t", dialect
2790 ).unwrap();
2791 annotate_types(&mut expression, None, Some(dialect));
2792 let Expression::Select(select) = expression else {
2793 panic!("select")
2794 };
2795 assert!(
2796 select.expressions[0]
2797 .inferred_type()
2798 .is_none_or(|t| *t == DataType::Unknown),
2799 "{dialect:?}: {:?}",
2800 select.expressions[0].inferred_type()
2801 );
2802 }
2803 }
2804
2805 #[test]
2806 fn set_operation_coercion_parameters_and_isolation_454() {
2807 use super::super::set_operation_types::common_type;
2808 let mut literal_query = parse_one(
2809 "SELECT t.a FROM (SELECT 1.5 AS a UNION ALL SELECT 2.5 AS a) AS t",
2810 DialectType::PostgreSQL,
2811 )
2812 .unwrap();
2813 annotate_types(&mut literal_query, None, Some(DialectType::PostgreSQL));
2814 let Expression::Select(select) = literal_query else {
2815 panic!("select")
2816 };
2817 assert!(matches!(
2818 select.expressions[0].inferred_type(),
2819 Some(DataType::Decimal {
2820 precision: None,
2821 scale: None
2822 })
2823 ));
2824 let dec = |p, s| DataType::Decimal {
2825 precision: Some(p),
2826 scale: Some(s),
2827 };
2828 let varchar = |n| DataType::VarChar {
2829 length: Some(n),
2830 parenthesized_length: false,
2831 };
2832 let array = |t| DataType::Array {
2833 element_type: Box::new(t),
2834 dimension: None,
2835 };
2836 let int = DataType::Int {
2837 length: None,
2838 integer_spelling: false,
2839 };
2840 let double = double_type();
2841 for dialect in [
2842 DialectType::TSQL,
2843 DialectType::DuckDB,
2844 DialectType::DataFusion,
2845 DialectType::Trino,
2846 ] {
2847 assert_eq!(
2848 common_type(&dec(10, 2), &dec(8, 4), dialect, 0),
2849 Some(dec(12, 4))
2850 );
2851 assert_eq!(
2852 common_type(&dec(8, 4), &dec(10, 2), dialect, 0),
2853 Some(dec(12, 4))
2854 );
2855 assert_eq!(
2856 common_type(&dec(10, 2), &DataType::Unknown, dialect, 0),
2857 None
2858 );
2859 assert_eq!(
2860 common_type(&array(int.clone()), &array(DataType::Unknown), dialect, 0),
2861 None
2862 );
2863 }
2864 assert_eq!(
2865 common_type(&varchar(10), &varchar(30), DialectType::TSQL, 0),
2866 Some(varchar(30))
2867 );
2868 assert_eq!(
2869 common_type(
2870 &array(int.clone()),
2871 &array(double.clone()),
2872 DialectType::DuckDB,
2873 0
2874 ),
2875 Some(array(double))
2876 );
2877 assert_eq!(
2878 common_type(
2879 &DataType::BigInt { length: None },
2880 &DataType::UInt64,
2881 DialectType::DuckDB,
2882 0
2883 ),
2884 Some(DataType::Int128)
2885 );
2886 assert_eq!(
2887 common_type(&dec(38, 20), &dec(38, 0), DialectType::TSQL, 0),
2888 Some(dec(38, 0))
2889 );
2890 assert_eq!(
2891 common_type(&dec(38, 20), &dec(38, 0), DialectType::Trino, 0),
2892 None
2893 );
2894 assert_eq!(
2895 common_type(&dec(10, 2), &double_type(), DialectType::DataFusion, 0),
2896 Some(dec(30, 15))
2897 );
2898 assert_eq!(
2899 common_type(
2900 &DataType::UInt64,
2901 &DataType::BigInt { length: None },
2902 DialectType::ClickHouse,
2903 0
2904 ),
2905 None
2906 );
2907 assert_eq!(
2908 common_type(
2909 &DataType::UInt64,
2910 &DataType::BigInt { length: None },
2911 DialectType::DataFusion,
2912 0
2913 ),
2914 Some(dec(20, 0))
2915 );
2916 let structure = |fields: Vec<(&str, DataType)>| DataType::Struct {
2917 fields: fields
2918 .into_iter()
2919 .map(|(name, t)| StructField::new(name.to_owned(), t))
2920 .collect(),
2921 nested: false,
2922 };
2923 let left = structure(vec![("x", int.clone()), ("y", varchar(10))]);
2924 let right = structure(vec![("y", varchar(30)), ("x", double_type())]);
2925 let combined = structure(vec![("x", double_type()), ("y", varchar(30))]);
2926 assert_eq!(
2927 common_type(&left, &right, DialectType::DataFusion, 0),
2928 Some(combined)
2929 );
2930 let right = structure(vec![("z", DataType::Boolean), ("x", double_type())]);
2931 assert_eq!(
2932 common_type(
2933 &structure(vec![("x", int.clone())]),
2934 &right,
2935 DialectType::DuckDB,
2936 0
2937 ),
2938 Some(structure(vec![
2939 ("x", double_type()),
2940 ("z", DataType::Boolean)
2941 ]))
2942 );
2943 assert_eq!(
2944 common_type(
2945 &array(int.clone()),
2946 &array(double_type()),
2947 DialectType::BigQuery,
2948 0
2949 ),
2950 None
2951 );
2952 let map = |value_type| DataType::Map {
2953 key_type: Box::new(DataType::Text),
2954 value_type: Box::new(value_type),
2955 };
2956 assert_eq!(
2957 common_type(
2958 &map(int.clone()),
2959 &map(double_type()),
2960 DialectType::DuckDB,
2961 0
2962 ),
2963 Some(map(double_type()))
2964 );
2965 let timestamp = |p| DataType::Timestamp {
2966 precision: Some(p),
2967 timezone: false,
2968 };
2969 assert_eq!(
2970 common_type(×tamp(3), ×tamp(6), DialectType::TSQL, 0),
2971 Some(timestamp(6))
2972 );
2973 assert_eq!(
2974 common_type(&DataType::Date, ×tamp(6), DialectType::PostgreSQL, 0),
2975 Some(timestamp(6))
2976 );
2977 for dialect in [
2978 DialectType::BigQuery,
2979 DialectType::Hive,
2980 DialectType::Databricks,
2981 DialectType::Generic,
2982 DialectType::BigQuery,
2983 ] {
2984 assert_eq!(common_type(&varchar(10), &DataType::Date, dialect, 0), None);
2985 }
2986 }
2987
2988 fn make_int_literal(val: i64) -> Expression {
2989 Expression::Literal(Box::new(Literal::Number(val.to_string())))
2990 }
2991
2992 fn make_float_literal(val: f64) -> Expression {
2993 Expression::Literal(Box::new(Literal::Number(val.to_string())))
2994 }
2995
2996 fn make_string_literal(val: &str) -> Expression {
2997 Expression::Literal(Box::new(Literal::String(val.to_string())))
2998 }
2999
3000 fn make_bool_literal(val: bool) -> Expression {
3001 Expression::Boolean(BooleanLiteral { value: val })
3002 }
3003
3004 #[test]
3005 fn test_cte_recursive_anchor_visibility_473() {
3006 for dialect in [DialectType::DuckDB, DialectType::PostgreSQL] {
3007 let mut schema = MappingSchema::with_dialect(dialect);
3008 schema
3009 .add_table(
3010 "orders",
3011 &[("id".into(), DataType::BigInt { length: None })],
3012 None,
3013 )
3014 .unwrap();
3015 for (sql, recursive) in [
3016 ("WITH orders AS (SELECT CAST(1 AS INT) AS id UNION ALL SELECT id FROM orders) SELECT id FROM orders", false),
3017 ("WITH orders(out_id) AS (SELECT CAST(1 AS INT) AS id UNION SELECT id FROM orders) SELECT out_id FROM orders", false),
3018 ("WITH RECURSIVE orders(id) AS (SELECT CAST(1 AS INT) AS id UNION ALL SELECT id + 1 FROM orders WHERE id < 3) SELECT id FROM orders", true),
3019 ] {
3020 let mut expression = parse_one(sql, dialect).unwrap();
3021 annotate_types(&mut expression, Some(&schema), Some(dialect));
3022 let Expression::Select(select) = expression else { panic!("select") };
3023 let actual = select.expressions[0].inferred_type();
3024 assert!(if recursive { matches!(actual, Some(DataType::Int { .. })) }
3025 else { matches!(actual, Some(DataType::BigInt { .. })) }, "{dialect}: {sql}: {actual:?}");
3026 }
3027 }
3028 for dialect in [
3029 DialectType::Snowflake,
3030 DialectType::TSQL,
3031 DialectType::Oracle,
3032 DialectType::SQLite,
3033 ] {
3034 let mut expression = parse_one(
3035 "WITH orders(id) AS (SELECT CAST(1 AS INT) AS id UNION ALL SELECT id + 1 FROM orders WHERE id < 3) SELECT id FROM orders",
3036 dialect,
3037 ).unwrap();
3038 annotate_types(&mut expression, None, Some(dialect));
3039 let Expression::Select(select) = expression else {
3040 panic!("select")
3041 };
3042 assert!(
3043 matches!(
3044 select.expressions[0].inferred_type(),
3045 Some(DataType::Int { .. })
3046 ),
3047 "{dialect}: {:?}",
3048 select.expressions[0].inferred_type()
3049 );
3050 }
3051 }
3052
3053 #[test]
3054 fn test_annotate_cte_bindings_exclude_unselected_definitions() {
3055 for sql in [
3056 "WITH a AS (SELECT CAST('1' AS INT) AS n), b AS (SELECT n FROM a) SELECT n FROM b",
3057 "WITH unused AS (SELECT CAST('x' AS TEXT) AS n), a AS (SELECT CAST('1' AS INT) AS n) SELECT n FROM a",
3058 "WITH a(n) AS (SELECT CAST('1' AS INT)), b(m) AS (SELECT n FROM a) SELECT m FROM b",
3059 ] {
3060 let mut expression = parse_one(sql, DialectType::DuckDB).unwrap();
3061 annotate_types(&mut expression, None, Some(DialectType::DuckDB));
3062 let Expression::Select(select) = expression else { panic!("select") };
3063 assert!(matches!(select.expressions[0].inferred_type(), Some(DataType::Int { .. })), "{sql}");
3064 }
3065 }
3066
3067 #[test]
3068 fn test_annotate_does_not_resolve_unselected_or_ambiguous_columns() {
3069 let mut schema = MappingSchema::new();
3070 schema
3071 .add_table("unrelated", &[("n".into(), DataType::Text)], None)
3072 .unwrap();
3073 for sql in [
3074 "SELECT n FROM missing",
3075 "SELECT unrelated.n FROM missing",
3076 "WITH a AS (SELECT 1 AS n), b AS (SELECT 2 AS n) SELECT n FROM a CROSS JOIN b",
3077 "WITH unused AS (SELECT 1 AS n) SELECT n FROM missing",
3078 ] {
3079 let mut expression = parse_one(sql, DialectType::DuckDB).unwrap();
3080 annotate_types(&mut expression, Some(&schema), Some(DialectType::DuckDB));
3081 let Expression::Select(select) = expression else {
3082 panic!("select")
3083 };
3084 assert!(select.expressions[0].inferred_type().is_none(), "{sql}");
3085 }
3086 }
3087
3088 #[test]
3089 fn test_literal_types() {
3090 let mut annotator = TypeAnnotator::new(None, None);
3091
3092 let int_expr = make_int_literal(42);
3094 assert_eq!(
3095 annotator.annotate(&int_expr),
3096 Some(DataType::Int {
3097 length: None,
3098 integer_spelling: false
3099 })
3100 );
3101
3102 let float_expr = make_float_literal(3.14);
3104 assert_eq!(
3105 annotator.annotate(&float_expr),
3106 Some(DataType::Double {
3107 precision: None,
3108 scale: None
3109 })
3110 );
3111
3112 let string_expr = make_string_literal("hello");
3114 assert_eq!(
3115 annotator.annotate(&string_expr),
3116 Some(DataType::VarChar {
3117 length: None,
3118 parenthesized_length: false
3119 })
3120 );
3121
3122 let bool_expr = make_bool_literal(true);
3124 assert_eq!(annotator.annotate(&bool_expr), Some(DataType::Boolean));
3125
3126 let null_expr = Expression::Null(Null);
3128 assert_eq!(annotator.annotate(&null_expr), None);
3129 }
3130
3131 #[test]
3132 fn test_comparison_types() {
3133 let mut annotator = TypeAnnotator::new(None, None);
3134
3135 let cmp = Expression::Gt(Box::new(BinaryOp::new(
3137 make_int_literal(1),
3138 make_int_literal(2),
3139 )));
3140 assert_eq!(annotator.annotate(&cmp), Some(DataType::Boolean));
3141
3142 let eq = Expression::Eq(Box::new(BinaryOp::new(
3144 make_string_literal("a"),
3145 make_string_literal("b"),
3146 )));
3147 assert_eq!(annotator.annotate(&eq), Some(DataType::Boolean));
3148 }
3149
3150 #[test]
3151 fn test_arithmetic_types() {
3152 let mut annotator = TypeAnnotator::new(None, None);
3153
3154 let add_int = Expression::Add(Box::new(BinaryOp::new(
3156 make_int_literal(1),
3157 make_int_literal(2),
3158 )));
3159 assert_eq!(
3160 annotator.annotate(&add_int),
3161 Some(DataType::Int {
3162 length: None,
3163 integer_spelling: false
3164 })
3165 );
3166
3167 let add_mixed = Expression::Add(Box::new(BinaryOp::new(
3169 make_int_literal(1),
3170 make_float_literal(2.5), )));
3172 assert_eq!(
3173 annotator.annotate(&add_mixed),
3174 Some(DataType::Double {
3175 precision: None,
3176 scale: None
3177 })
3178 );
3179 }
3180
3181 #[test]
3182 fn test_string_concat_type() {
3183 let mut annotator = TypeAnnotator::new(None, None);
3184
3185 let concat = Expression::Concat(Box::new(BinaryOp::new(
3187 make_string_literal("hello"),
3188 make_string_literal(" world"),
3189 )));
3190 assert_eq!(
3191 annotator.annotate(&concat),
3192 Some(DataType::VarChar {
3193 length: None,
3194 parenthesized_length: false
3195 })
3196 );
3197 }
3198
3199 #[test]
3200 fn test_cast_type() {
3201 let mut annotator = TypeAnnotator::new(None, None);
3202
3203 let cast = Expression::Cast(Box::new(Cast {
3205 this: make_int_literal(1),
3206 to: DataType::VarChar {
3207 length: Some(10),
3208 parenthesized_length: false,
3209 },
3210 trailing_comments: vec![],
3211 double_colon_syntax: false,
3212 format: None,
3213 default: None,
3214 inferred_type: None,
3215 }));
3216 assert_eq!(
3217 annotator.annotate(&cast),
3218 Some(DataType::VarChar {
3219 length: Some(10),
3220 parenthesized_length: false
3221 })
3222 );
3223 }
3224
3225 #[test]
3226 fn test_function_types() {
3227 let mut annotator = TypeAnnotator::new(None, None);
3228
3229 let count =
3231 Expression::Function(Box::new(Function::new("COUNT", vec![make_int_literal(1)])));
3232 assert_eq!(
3233 annotator.annotate(&count),
3234 Some(DataType::BigInt { length: None })
3235 );
3236
3237 let upper = Expression::Function(Box::new(Function::new(
3239 "UPPER",
3240 vec![make_string_literal("hello")],
3241 )));
3242 assert_eq!(
3243 annotator.annotate(&upper),
3244 Some(DataType::VarChar {
3245 length: None,
3246 parenthesized_length: false
3247 })
3248 );
3249
3250 let now = Expression::Function(Box::new(Function::new("NOW", vec![])));
3252 assert_eq!(
3253 annotator.annotate(&now),
3254 Some(DataType::Timestamp {
3255 precision: None,
3256 timezone: false
3257 })
3258 );
3259 }
3260
3261 #[test]
3262 fn test_duckdb_trim_stores_inferred_types() {
3263 let varchar = DataType::VarChar {
3264 length: None,
3265 parenthesized_length: false,
3266 };
3267 let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
3268 schema
3269 .add_table(
3270 "records",
3271 &[
3272 ("name".to_string(), varchar.clone()),
3273 ("chars".to_string(), varchar.clone()),
3274 ("values_json".to_string(), DataType::Json),
3275 ],
3276 None,
3277 )
3278 .unwrap();
3279
3280 for function in [
3281 "TRIM(name)",
3282 "trim(records.name)",
3283 "TRIM(name, chars)",
3284 "TRIM(BOTH chars FROM name)",
3285 "TRIM(LEADING chars FROM name)",
3286 "TRIM(TRAILING chars FROM name)",
3287 "TRIM(FROM name)",
3288 "TRIM(' hello ')",
3289 "TRIM(NULL)",
3290 r#"TRIM(BOTH '"' FROM values_json->>0)"#,
3291 ] {
3292 let sql = format!("SELECT {function} AS normalized FROM records");
3293 for schema in [None, Some(&schema as &dyn Schema)] {
3294 let mut expression = parse_one(&sql, DialectType::DuckDB).unwrap();
3295 let original_sql = expression.sql_for(DialectType::DuckDB);
3296 annotate_types(&mut expression, schema, Some(DialectType::DuckDB));
3297 let Expression::Select(select) = &expression else {
3298 panic!("Expected SELECT for {sql}");
3299 };
3300 let Expression::Alias(alias) = &select.expressions[0] else {
3301 panic!("Expected alias for {sql}");
3302 };
3303 assert!(matches!(alias.this, Expression::Trim(_)), "{sql}");
3304 assert_eq!(alias.this.inferred_type(), Some(&varchar), "{sql}");
3305 assert_eq!(alias.inferred_type.as_ref(), Some(&varchar), "{sql}");
3306 assert_eq!(expression.sql_for(DialectType::DuckDB), original_sql);
3307 }
3308 }
3309 }
3310
3311 #[test]
3312 fn test_int128_inferred_types_and_widening() {
3313 let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
3314 schema
3315 .add_table(
3316 "measurements",
3317 &[("value".to_string(), DataType::Int128)],
3318 None,
3319 )
3320 .unwrap();
3321 for (projection, expected) in [
3322 ("CAST(value AS HUGEINT)", DataType::Int128),
3323 ("value", DataType::Int128),
3324 ("value + CAST(1 AS BIGINT)", DataType::Int128),
3325 ("CAST(1 AS BIGINT) + value", DataType::Int128),
3326 ("COALESCE(value, CAST(1 AS BIGINT))", DataType::Int128),
3327 ("COALESCE(CAST(1 AS BIGINT), value)", DataType::Int128),
3328 (
3329 "CASE WHEN TRUE THEN value ELSE CAST(1 AS BIGINT) END",
3330 DataType::Int128,
3331 ),
3332 ("SUM(value)", DataType::Int128),
3333 ("SUM(CAST(value AS BIGINT))", DataType::Int128),
3334 (
3335 "MEDIAN(value)",
3336 DataType::Double {
3337 precision: None,
3338 scale: None,
3339 },
3340 ),
3341 (
3342 "CAST(value AS HUGEINT[])",
3343 DataType::Array {
3344 element_type: Box::new(DataType::Int128),
3345 dimension: None,
3346 },
3347 ),
3348 ] {
3349 let sql = format!("SELECT {projection} AS widened FROM measurements");
3350 let mut expression = parse_one(&sql, DialectType::DuckDB).unwrap();
3351 annotate_types(&mut expression, Some(&schema), Some(DialectType::DuckDB));
3352 let Expression::Select(select) = &expression else {
3353 panic!("expected SELECT")
3354 };
3355 let Expression::Alias(alias) = &select.expressions[0] else {
3356 panic!("expected alias")
3357 };
3358 assert_eq!(alias.this.inferred_type(), Some(&expected), "{sql}");
3359 assert_eq!(alias.inferred_type.as_ref(), Some(&expected), "{sql}");
3360 }
3361 assert_eq!(
3362 TypeCoercionClass::from_data_type(&DataType::Int128),
3363 Some(TypeCoercionClass::Numeric)
3364 );
3365 }
3366
3367 #[test]
3368 fn test_duckdb_unsigned_integer_coercion_matrix() {
3369 let signed = ["TINYINT", "SMALLINT", "INT", "BIGINT", "HUGEINT"];
3372 let unsigned = ["UTINYINT", "USMALLINT", "UINTEGER", "UBIGINT", "UHUGEINT"];
3373 let arithmetic = [
3374 ["BIGINT", "BIGINT", "BIGINT", "HUGEINT", "DOUBLE"],
3375 ["SMALLINT", "BIGINT", "BIGINT", "HUGEINT", "DOUBLE"],
3376 ["INT", "INT", "BIGINT", "HUGEINT", "DOUBLE"],
3377 ["BIGINT", "BIGINT", "BIGINT", "HUGEINT", "DOUBLE"],
3378 ["HUGEINT", "HUGEINT", "HUGEINT", "HUGEINT", "DOUBLE"],
3379 ];
3380 let combination = [
3381 ["SMALLINT", "INT", "BIGINT", "HUGEINT", "SMALLINT"],
3382 ["SMALLINT", "INT", "BIGINT", "HUGEINT", "INT"],
3383 ["INT", "INT", "BIGINT", "HUGEINT", "BIGINT"],
3384 ["BIGINT", "BIGINT", "BIGINT", "HUGEINT", "HUGEINT"],
3385 ["HUGEINT", "HUGEINT", "HUGEINT", "HUGEINT", "DOUBLE"],
3386 ];
3387 for (i, s) in signed.iter().enumerate() {
3388 for (j, u) in unsigned.iter().enumerate() {
3389 for (a, b) in [(s, u), (u, s)] {
3390 let a = format!("CAST(1 AS {a})");
3391 let b = format!("CAST(1 AS {b})");
3392 for (sql, expected) in [
3393 (format!("{a} + {b}"), arithmetic[i][j]),
3394 (format!("{a} - {b}"), arithmetic[i][j]),
3395 (format!("{a} * {b}"), arithmetic[i][j]),
3396 (format!("{a} % {b}"), arithmetic[i][j]),
3397 (format!("{a} / {b}"), "DOUBLE"),
3398 (format!("COALESCE({a}, {b})"), combination[i][j]),
3399 (
3400 format!("CASE WHEN TRUE THEN {a} ELSE {b} END"),
3401 combination[i][j],
3402 ),
3403 ] {
3404 let expr = parse_one(&sql, DialectType::DuckDB).unwrap();
3405 let expected =
3406 crate::parse_data_type(expected, DialectType::DuckDB).unwrap();
3407 let mut annotator = TypeAnnotator::new(None, Some(DialectType::DuckDB));
3408 assert_eq!(annotator.annotate(&expr), Some(expected), "{sql}");
3409 }
3410 }
3411 }
3412 }
3413 for (i, a) in unsigned.iter().enumerate() {
3414 for (j, b) in unsigned.iter().enumerate() {
3415 let sql = format!("CAST(1 AS {a}) + CAST(1 AS {b})");
3416 let expr = parse_one(&sql, DialectType::DuckDB).unwrap();
3417 let mut annotator = TypeAnnotator::new(None, Some(DialectType::DuckDB));
3418 assert_eq!(
3419 annotator.annotate(&expr),
3420 Some(crate::parse_data_type(unsigned[i.max(j)], DialectType::DuckDB).unwrap()),
3421 "{sql}"
3422 );
3423 }
3424 }
3425 }
3426
3427 #[test]
3428 fn test_duckdb_sum_return_types() {
3429 for (input, output) in [
3430 ("BOOLEAN", "INT128"),
3431 ("TINYINT", "INT128"),
3432 ("SMALLINT", "INT128"),
3433 ("INT", "INT128"),
3434 ("BIGINT", "INT128"),
3435 ("HUGEINT", "INT128"),
3436 ("UTINYINT", "INT128"),
3437 ("USMALLINT", "INT128"),
3438 ("UINTEGER", "INT128"),
3439 ("UBIGINT", "INT128"),
3440 ("UHUGEINT", "DOUBLE"),
3441 ("FLOAT", "DOUBLE"),
3442 ("DOUBLE", "DOUBLE"),
3443 ("DECIMAL(10,2)", "DECIMAL(38,2)"),
3444 ("DECIMAL", "DECIMAL(38,3)"),
3445 ("DECIMAL(10)", "DECIMAL(38,0)"),
3446 ] {
3447 let input_type = crate::parse_data_type(input, DialectType::DuckDB).unwrap();
3448 let expected = crate::parse_data_type(output, DialectType::DuckDB).unwrap();
3449 let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
3450 schema
3451 .add_table("t", &[("x".to_string(), input_type)], None)
3452 .unwrap();
3453 let cast = parse_one(&format!("CAST(1 AS {input})"), DialectType::DuckDB).unwrap();
3454 let function = Expression::Function(Box::new(Function::new("SUM", vec![cast])));
3455 assert_eq!(
3456 TypeAnnotator::new(None, Some(DialectType::DuckDB)).annotate(&function),
3457 Some(expected.clone()),
3458 "SUM({input}) builder"
3459 );
3460 for arg in ["x".to_string(), format!("CAST(1 AS {input})")] {
3461 for projection in [
3462 format!("SUM({arg})"),
3463 format!("SUM(DISTINCT {arg})"),
3464 format!("SUM({arg}) OVER ()"),
3465 format!("SUM({arg}) FILTER (WHERE TRUE)"),
3466 ] {
3467 let sql = format!("SELECT {projection} AS total FROM t");
3468 let mut expr = parse_one(&sql, DialectType::DuckDB).unwrap();
3469 annotate_types(&mut expr, Some(&schema), Some(DialectType::DuckDB));
3470 let Expression::Select(select) = expr else {
3471 unreachable!()
3472 };
3473 let Expression::Alias(alias) = &select.expressions[0] else {
3474 unreachable!()
3475 };
3476 assert_eq!(alias.inferred_type.as_ref(), Some(&expected), "{sql}");
3477 }
3478 }
3479 }
3480 let expr = parse_one("SUM(x)", DialectType::DuckDB).unwrap();
3481 assert_eq!(
3482 TypeAnnotator::new(None, Some(DialectType::DuckDB)).annotate(&expr),
3483 None
3484 );
3485 for dialect in [
3487 DialectType::Generic,
3488 DialectType::PostgreSQL,
3489 DialectType::MySQL,
3490 DialectType::BigQuery,
3491 ] {
3492 let expr = parse_one("SUM(CAST(1 AS BIGINT))", dialect).unwrap();
3493 assert_eq!(
3494 TypeAnnotator::new(None, Some(dialect)).annotate(&expr),
3495 Some(DataType::BigInt { length: None })
3496 );
3497 }
3498 }
3499
3500 #[test]
3501 fn test_trim_annotates_both_arguments_and_nested_children() {
3502 let varchar = DataType::VarChar {
3503 length: None,
3504 parenthesized_length: false,
3505 };
3506 let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
3507 schema
3508 .add_table(
3509 "users",
3510 &[
3511 ("name".to_string(), varchar.clone()),
3512 ("chars".to_string(), varchar.clone()),
3513 ],
3514 None,
3515 )
3516 .unwrap();
3517
3518 fn check_children(expr: &Expression, varchar: &DataType, has_schema: bool) -> usize {
3519 let mut count = 0;
3520 if matches!(
3521 expr,
3522 Expression::Trim(_)
3523 | Expression::Lower(_)
3524 | Expression::Upper(_)
3525 | Expression::Column(_)
3526 ) {
3527 let expected = if matches!(expr, Expression::Column(_)) && !has_schema {
3528 None
3529 } else {
3530 Some(varchar)
3531 };
3532 assert_eq!(expr.inferred_type(), expected, "{}", expr.sql());
3533 count += 1;
3534 }
3535 crate::ast_children::for_each_child(expr, |_, child| {
3536 count += check_children(child, varchar, has_schema);
3537 });
3538 count
3539 }
3540
3541 for schema in [None, Some(&schema as &dyn Schema)] {
3542 let mut expression = parse_one(
3543 "SELECT TRIM(LOWER(TRIM(name)), UPPER(chars)) AS normalized FROM users",
3544 DialectType::DuckDB,
3545 )
3546 .unwrap();
3547 annotate_types(&mut expression, schema, Some(DialectType::DuckDB));
3548 assert_eq!(check_children(&expression, &varchar, schema.is_some()), 6);
3549 }
3550 }
3551
3552 #[test]
3553 fn test_trim_type_metadata_roundtrip_across_dialects() {
3554 let varchar = DataType::VarChar {
3555 length: None,
3556 parenthesized_length: false,
3557 };
3558 for dialect in [
3559 DialectType::Generic,
3560 DialectType::DuckDB,
3561 DialectType::PostgreSQL,
3562 DialectType::Snowflake,
3563 DialectType::BigQuery,
3564 DialectType::MySQL,
3565 ] {
3566 let expression = parse_one("TRIM(' hello ')", dialect).unwrap();
3567 assert!(matches!(expression, Expression::Trim(_)));
3568 assert_eq!(expression.inferred_type(), None);
3569 let unannotated = serde_json::to_value(&expression).unwrap();
3570 assert!(unannotated["trim"].get("inferred_type").is_none());
3571
3572 let mut restored: Expression = serde_json::from_value(unannotated).unwrap();
3574 assert_eq!(restored, expression);
3575 annotate_types(&mut restored, None, Some(dialect));
3576 assert_eq!(restored.inferred_type(), Some(&varchar), "{dialect:?}");
3577 assert_eq!(restored.sql_for(dialect), expression.sql_for(dialect));
3578
3579 let annotated = serde_json::to_value(&restored).unwrap();
3580 assert_eq!(annotated["trim"]["inferred_type"]["data_type"], "var_char");
3581 let roundtripped: Expression = serde_json::from_value(annotated).unwrap();
3582 assert_eq!(roundtripped, restored);
3583 assert_eq!(roundtripped.inferred_type(), Some(&varchar));
3584 }
3585 }
3586
3587 #[test]
3588 fn test_duckdb_regexp_extract_all_overload_types() {
3589 let varchar = DataType::VarChar {
3590 length: None,
3591 parenthesized_length: false,
3592 };
3593 let captures = DataType::Struct {
3594 fields: vec![
3595 StructField::new("Letter".to_string(), varchar.clone()),
3596 StructField::new("number".to_string(), varchar.clone()),
3597 ],
3598 nested: false,
3599 };
3600 let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
3601 schema
3602 .add_table("documents", &[("body".to_string(), varchar.clone())], None)
3603 .unwrap();
3604
3605 for (arguments, element_type) in [
3606 ("body, '[0-9]+'", &varchar),
3607 ("documents.body, '[0-9]+'", &varchar),
3608 ("'a1b22', '[0-9]+'", &varchar),
3609 ("'abc', '[0-9]+'", &varchar),
3610 ("NULL, '[0-9]+'", &varchar),
3611 ("body, '([a-z])([0-9]+)', 0", &varchar),
3612 ("body, '([a-z])([0-9]+)', 2", &varchar),
3613 ("body, '([a-z])([0-9]+)', (1), 'i'", &varchar),
3614 ("body, '([a-z])([0-9]+)', CAST(1 AS INTEGER)", &varchar),
3615 ("body, '([a-z])([0-9]+)', NULL", &varchar),
3616 ("body, '([a-z])([0-9]+)', ['Letter', 'number']", &captures),
3617 (
3618 "body, '([a-z])([0-9]+)', (['Letter', 'number']), 'i'",
3619 &captures,
3620 ),
3621 (
3622 "body, '([a-z])([0-9]+)', ARRAY['Letter', 'number']",
3623 &captures,
3624 ),
3625 (
3626 "NULL, '([a-z])([0-9]+)', LIST['Letter', 'number']",
3627 &captures,
3628 ),
3629 ] {
3630 let expected = DataType::Array {
3631 element_type: Box::new(element_type.clone()),
3632 dimension: None,
3633 };
3634 for name in ["REGEXP_EXTRACT_ALL", "ReGeXp_ExTrAcT_AlL"] {
3635 for schema in [None, Some(&schema as &dyn Schema)] {
3636 let sql = format!("SELECT {name}({arguments}) AS matches FROM documents");
3637 let mut expression = parse_one(&sql, DialectType::DuckDB).unwrap();
3638 let original_sql = expression.sql_for(DialectType::DuckDB);
3639 annotate_types(&mut expression, schema, Some(DialectType::DuckDB));
3640 let Expression::Select(select) = &expression else {
3641 panic!("Expected SELECT for {sql}");
3642 };
3643 let Expression::Alias(alias) = &select.expressions[0] else {
3644 panic!("Expected alias for {sql}");
3645 };
3646 assert_eq!(alias.this.inferred_type(), Some(&expected), "{sql}");
3647 assert_eq!(alias.inferred_type.as_ref(), Some(&expected), "{sql}");
3648 assert_eq!(expression.sql_for(DialectType::DuckDB), original_sql);
3649 let json = serde_json::to_value(&expression).unwrap();
3650 let restored: Expression = serde_json::from_value(json).unwrap();
3651 assert_eq!(restored, expression);
3652
3653 let sql = format!(
3654 "SELECT UNNEST({name}({arguments})) AS single_match FROM documents"
3655 );
3656 let mut expression = parse_one(&sql, DialectType::DuckDB).unwrap();
3657 annotate_types(&mut expression, schema, Some(DialectType::DuckDB));
3658 let Expression::Select(select) = &expression else {
3659 panic!("Expected SELECT for {sql}");
3660 };
3661 let Expression::Alias(alias) = &select.expressions[0] else {
3662 panic!("Expected alias for {sql}");
3663 };
3664 assert_eq!(alias.this.inferred_type(), Some(element_type), "{sql}");
3665 assert_eq!(alias.inferred_type.as_ref(), Some(element_type), "{sql}");
3666 }
3667 }
3668 }
3669 }
3670
3671 #[test]
3672 fn test_duckdb_regexp_extract_all_unresolved_overloads() {
3673 let varchar = DataType::VarChar {
3674 length: None,
3675 parenthesized_length: false,
3676 };
3677 let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
3678 schema
3679 .add_table(
3680 "documents",
3681 &[(
3682 "names".to_string(),
3683 DataType::Array {
3684 element_type: Box::new(varchar),
3685 dimension: None,
3686 },
3687 )],
3688 None,
3689 )
3690 .unwrap();
3691
3692 for arguments in [
3695 "",
3696 "'a1'",
3697 "'a1', '(a)(1)', 0, 'i', 1",
3698 "'a1', '(a)(1)', missing_group",
3699 "'a1', '(a)(1)', documents.names",
3700 "'a1', '(a)(1)', ['letter', missing_name]",
3701 "'a1', '(a)(1)', CAST(['letter', 'number'] AS VARCHAR[])",
3702 "'a1', '(a)(1)', []",
3703 "'a1', '(a)(1)', [NULL]",
3704 "'a1', '(a)(1)', ['letter', 'LETTER']",
3705 "'a1', '(a)(1)', 1.0",
3706 "'a1', '(a)(1)', CAST(1 AS BIGINT)",
3707 ] {
3708 let sql = format!("REGEXP_EXTRACT_ALL({arguments})");
3709 let mut expression = parse_one(&sql, DialectType::DuckDB).unwrap();
3710 let mut annotator = TypeAnnotator::new(Some(&schema), Some(DialectType::DuckDB));
3711 assert_eq!(annotator.annotate(&expression), None, "{sql}");
3712 annotator.annotate_in_place(&mut expression);
3713 assert_eq!(expression.inferred_type(), None, "{sql}");
3714 }
3715 }
3716
3717 #[test]
3718 fn test_regexp_extract_all_rule_is_duckdb_specific() {
3719 for dialect in [
3722 None,
3723 Some(DialectType::Generic),
3724 Some(DialectType::BigQuery),
3725 Some(DialectType::Snowflake),
3726 Some(DialectType::Databricks),
3727 ] {
3728 for input in [
3729 make_string_literal("a1"),
3730 Expression::Literal(Box::new(Literal::ByteString("a1".to_string()))),
3731 ] {
3732 let mut annotator = TypeAnnotator::new(None, dialect);
3733 let expected = annotator.annotate(&input);
3734 let function = Expression::Function(Box::new(Function::new(
3735 "REGEXP_EXTRACT_ALL",
3736 vec![input, make_string_literal("[0-9]+")],
3737 )));
3738 assert_eq!(annotator.annotate(&function), expected, "{dialect:?}");
3739 }
3740 }
3741 }
3742
3743 #[test]
3744 fn test_duckdb_date_name_types() {
3745 let varchar = DataType::VarChar {
3746 length: None,
3747 parenthesized_length: false,
3748 };
3749 for input_type in [
3750 DataType::Date,
3751 DataType::Timestamp {
3752 precision: None,
3753 timezone: false,
3754 },
3755 DataType::Timestamp {
3756 precision: None,
3757 timezone: true,
3758 },
3759 ] {
3760 let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
3761 schema
3762 .add_table(
3763 "events",
3764 &[("created_at".to_string(), input_type.clone())],
3765 None,
3766 )
3767 .unwrap();
3768 for function in ["MONTHNAME", "MoNtHnAmE", "DAYNAME", "DaYnAmE"] {
3769 for input in [
3770 "created_at",
3771 "events.created_at",
3772 "DATE '2026-01-01'",
3773 "TIMESTAMP '2026-01-01 12:00:00'",
3774 "TIMESTAMPTZ '2026-01-01 12:00:00+00'",
3775 "NULL",
3776 ] {
3777 let sql = format!("SELECT {function}({input}) AS label FROM events");
3778 for schema in [None, Some(&schema as &dyn Schema)] {
3779 let mut expression = parse_one(&sql, DialectType::DuckDB).unwrap();
3780 let original_sql = expression.sql_for(DialectType::DuckDB);
3781 annotate_types(&mut expression, schema, Some(DialectType::DuckDB));
3782 let Expression::Select(select) = &expression else {
3783 panic!("Expected SELECT for {sql}");
3784 };
3785 let Expression::Alias(alias) = &select.expressions[0] else {
3786 panic!("Expected alias for {sql}");
3787 };
3788 assert_eq!(alias.this.inferred_type(), Some(&varchar), "{sql}");
3789 assert_eq!(alias.inferred_type.as_ref(), Some(&varchar), "{sql}");
3790 if let Expression::Function(function) = &alias.this {
3791 if let Expression::Column(column) = &function.args[0] {
3792 assert_eq!(
3793 column.inferred_type.as_ref(),
3794 schema.map(|_| &input_type),
3795 "Argument type must remain unchanged for {sql}"
3796 );
3797 }
3798 }
3799 assert_eq!(expression.sql_for(DialectType::DuckDB), original_sql);
3800 let json = serde_json::to_value(&expression).unwrap();
3801 let restored: Expression = serde_json::from_value(json).unwrap();
3802 assert_eq!(restored, expression);
3803 }
3804 }
3805 }
3806 }
3807 }
3808
3809 #[test]
3810 fn test_date_name_fixed_return_types_are_duckdb_specific() {
3811 for dialect in [
3812 None,
3813 Some(DialectType::Generic),
3814 Some(DialectType::PostgreSQL),
3815 Some(DialectType::MySQL),
3816 Some(DialectType::Snowflake),
3817 ] {
3818 let annotator = TypeAnnotator::new(None, dialect);
3819 for function in ["MONTHNAME", "DAYNAME"] {
3820 assert!(
3821 !annotator.function_return_types.contains_key(function),
3822 "Unexpected fixed return type for {function} in {dialect:?}"
3823 );
3824 }
3825 }
3826 }
3827
3828 #[test]
3829 fn test_duckdb_array_to_string_types() {
3830 let varchar = DataType::VarChar {
3831 length: None,
3832 parenthesized_length: false,
3833 };
3834 let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
3835 schema
3836 .add_table(
3837 "events",
3838 &[
3839 ("label".to_string(), varchar.clone()),
3840 (
3841 "labels".to_string(),
3842 DataType::Array {
3843 element_type: Box::new(varchar.clone()),
3844 dimension: None,
3845 },
3846 ),
3847 ],
3848 None,
3849 )
3850 .unwrap();
3851
3852 for function in [
3853 "ARRAY_TO_STRING",
3854 "array_to_string",
3855 "ArRaY_To_StRiNg_CoMmA_DeFaUlT",
3856 ] {
3857 for input in [
3858 "labels",
3859 "events.labels",
3860 "ARRAY_AGG(label)",
3861 "ARRAY_AGG(events.label)",
3862 "['a', NULL, 'b']",
3863 "[1, 2]",
3864 "[]",
3865 "CAST(NULL AS VARCHAR[])",
3866 "NULL",
3867 ] {
3868 let arguments = if function.eq_ignore_ascii_case("ARRAY_TO_STRING") {
3869 format!("{input}, ', '")
3870 } else {
3871 input.to_string()
3872 };
3873 let sql = format!("SELECT {function}({arguments}) AS label_text FROM events");
3874 for schema in [None, Some(&schema as &dyn Schema)] {
3875 let mut expression = parse_one(&sql, DialectType::DuckDB).unwrap();
3876 annotate_types(&mut expression, schema, Some(DialectType::DuckDB));
3877 let Expression::Select(select) = &expression else {
3878 panic!("Expected SELECT for {sql}");
3879 };
3880 let Expression::Alias(alias) = &select.expressions[0] else {
3881 panic!("Expected alias for {sql}");
3882 };
3883 assert_eq!(alias.this.inferred_type(), Some(&varchar), "{sql}");
3884 assert_eq!(alias.inferred_type.as_ref(), Some(&varchar), "{sql}");
3885 }
3886 }
3887 }
3888 }
3889
3890 #[test]
3891 fn test_array_to_string_fixed_return_types_are_duckdb_specific() {
3892 for dialect in [
3895 None,
3896 Some(DialectType::Generic),
3897 Some(DialectType::BigQuery),
3898 Some(DialectType::PostgreSQL),
3899 Some(DialectType::Snowflake),
3900 ] {
3901 let annotator = TypeAnnotator::new(None, dialect);
3902 for function in ["ARRAY_TO_STRING", "ARRAY_TO_STRING_COMMA_DEFAULT"] {
3903 assert!(
3904 !annotator.function_return_types.contains_key(function),
3905 "Unexpected fixed return type for {function} in {dialect:?}"
3906 );
3907 }
3908 }
3909 }
3910
3911 #[test]
3912 fn test_extract_types_are_dialect_and_field_specific() {
3913 let double = DataType::Double {
3914 precision: None,
3915 scale: None,
3916 };
3917 let bigint = DataType::BigInt { length: None };
3918 let int = DataType::Int {
3919 length: None,
3920 integer_spelling: false,
3921 };
3922
3923 for (field, duckdb_type) in [
3924 (DateTimeField::Year, &bigint),
3925 (DateTimeField::Second, &bigint),
3926 (DateTimeField::Millisecond, &bigint),
3927 (DateTimeField::Microsecond, &bigint),
3928 (DateTimeField::Custom("yearweek".to_string()), &bigint),
3929 (DateTimeField::Epoch, &double),
3930 (DateTimeField::Custom("EpOcH".to_string()), &double),
3931 (DateTimeField::Custom("julian".to_string()), &double),
3932 (DateTimeField::Custom("JuLiAn".to_string()), &double),
3933 ] {
3934 let extract = Expression::Extract(Box::new(ExtractFunc {
3935 this: make_string_literal("2024-02-03 04:05:06.123456"),
3936 field,
3937 }));
3938 for dialect in [
3939 None,
3940 Some(DialectType::Generic),
3941 Some(DialectType::PostgreSQL),
3942 Some(DialectType::Snowflake),
3943 Some(DialectType::DuckDB),
3944 ] {
3945 let expected = if dialect == Some(DialectType::DuckDB) {
3946 duckdb_type
3947 } else {
3948 &int
3949 };
3950 assert_eq!(
3951 TypeAnnotator::new(None, dialect)
3952 .annotate(&extract)
3953 .as_ref(),
3954 Some(expected),
3955 "unexpected type for {extract:?} in {dialect:?}"
3956 );
3957 }
3958 }
3959 }
3960
3961 #[test]
3962 fn test_duckdb_date_trunc_overload_types() {
3963 fn cast_to(data_type: DataType) -> Expression {
3964 Expression::Cast(Box::new(Cast {
3965 this: make_string_literal("value"),
3966 to: data_type,
3967 format: None,
3968 trailing_comments: Vec::new(),
3969 double_colon_syntax: false,
3970 default: None,
3971 inferred_type: None,
3972 }))
3973 }
3974
3975 fn date_trunc(value: Expression) -> Expression {
3976 Expression::Function(Box::new(Function::new(
3977 "DATE_TRUNC",
3978 vec![make_string_literal("month"), value],
3979 )))
3980 }
3981
3982 let mut annotator = TypeAnnotator::new(None, Some(DialectType::DuckDB));
3983
3984 for input_type in [
3985 DataType::Date,
3986 DataType::Timestamp {
3987 precision: Some(9),
3988 timezone: false,
3989 },
3990 ] {
3991 assert_eq!(
3992 annotator.annotate(&date_trunc(cast_to(input_type))),
3993 Some(DataType::Timestamp {
3994 precision: None,
3995 timezone: false,
3996 })
3997 );
3998 }
3999
4000 assert_eq!(
4001 annotator.annotate(&date_trunc(cast_to(DataType::Timestamp {
4002 precision: Some(6),
4003 timezone: true,
4004 }))),
4005 Some(DataType::Timestamp {
4006 precision: None,
4007 timezone: true,
4008 })
4009 );
4010 assert_eq!(
4011 annotator.annotate(&date_trunc(cast_to(DataType::Interval {
4012 unit: Some("DAY".to_string()),
4013 to: Some("SECOND".to_string()),
4014 }))),
4015 Some(DataType::Interval {
4016 unit: None,
4017 to: None,
4018 })
4019 );
4020 assert_eq!(
4021 annotator.annotate(&date_trunc(Expression::Null(Null))),
4022 None
4023 );
4024 }
4025
4026 #[test]
4027 fn test_coalesce_type_inference() {
4028 let mut annotator = TypeAnnotator::new(None, None);
4029
4030 let coalesce = Expression::Function(Box::new(Function::new(
4032 "COALESCE",
4033 vec![Expression::Null(Null), make_int_literal(1)],
4034 )));
4035 assert_eq!(
4036 annotator.annotate(&coalesce),
4037 Some(DataType::Int {
4038 length: None,
4039 integer_spelling: false
4040 })
4041 );
4042
4043 let specialized_coalesce = Expression::Coalesce(Box::new(crate::expressions::VarArgFunc {
4044 expressions: vec![Expression::Null(Null), make_int_literal(1)],
4045 original_name: None,
4046 inferred_type: None,
4047 }));
4048 assert_eq!(
4049 annotator.annotate(&specialized_coalesce),
4050 Some(DataType::Int {
4051 length: None,
4052 integer_spelling: false
4053 })
4054 );
4055 }
4056
4057 #[test]
4058 fn test_type_coercion_class() {
4059 assert_eq!(
4061 TypeCoercionClass::from_data_type(&DataType::VarChar {
4062 length: None,
4063 parenthesized_length: false
4064 }),
4065 Some(TypeCoercionClass::Text)
4066 );
4067 assert_eq!(
4068 TypeCoercionClass::from_data_type(&DataType::Text),
4069 Some(TypeCoercionClass::Text)
4070 );
4071
4072 assert_eq!(
4074 TypeCoercionClass::from_data_type(&DataType::Int {
4075 length: None,
4076 integer_spelling: false
4077 }),
4078 Some(TypeCoercionClass::Numeric)
4079 );
4080 assert_eq!(
4081 TypeCoercionClass::from_data_type(&DataType::Double {
4082 precision: None,
4083 scale: None
4084 }),
4085 Some(TypeCoercionClass::Numeric)
4086 );
4087
4088 assert_eq!(
4090 TypeCoercionClass::from_data_type(&DataType::Date),
4091 Some(TypeCoercionClass::Timelike)
4092 );
4093 assert_eq!(
4094 TypeCoercionClass::from_data_type(&DataType::Timestamp {
4095 precision: None,
4096 timezone: false
4097 }),
4098 Some(TypeCoercionClass::Timelike)
4099 );
4100
4101 assert_eq!(TypeCoercionClass::from_data_type(&DataType::Json), None);
4103 }
4104
4105 #[test]
4106 fn test_wider_numeric_type() {
4107 let annotator = TypeAnnotator::new(None, None);
4108
4109 let result = annotator.wider_numeric_type(
4111 &DataType::Int {
4112 length: None,
4113 integer_spelling: false,
4114 },
4115 &DataType::BigInt { length: None },
4116 );
4117 assert_eq!(result, DataType::BigInt { length: None });
4118
4119 let result = annotator.wider_numeric_type(
4121 &DataType::Float {
4122 precision: None,
4123 scale: None,
4124 real_spelling: false,
4125 },
4126 &DataType::Double {
4127 precision: None,
4128 scale: None,
4129 },
4130 );
4131 assert_eq!(
4132 result,
4133 DataType::Double {
4134 precision: None,
4135 scale: None
4136 }
4137 );
4138
4139 let result = annotator.wider_numeric_type(
4141 &DataType::Int {
4142 length: None,
4143 integer_spelling: false,
4144 },
4145 &DataType::Double {
4146 precision: None,
4147 scale: None,
4148 },
4149 );
4150 assert_eq!(
4151 result,
4152 DataType::Double {
4153 precision: None,
4154 scale: None
4155 }
4156 );
4157 }
4158
4159 #[test]
4160 fn test_aggregate_return_types() {
4161 let mut annotator = TypeAnnotator::new(None, None);
4162
4163 let sum_type = annotator.get_aggregate_return_type("SUM", &[make_int_literal(1)]);
4165 assert_eq!(sum_type, Some(DataType::BigInt { length: None }));
4166
4167 let avg_type = annotator.get_aggregate_return_type("AVG", &[make_int_literal(1)]);
4169 assert_eq!(
4170 avg_type,
4171 Some(DataType::Double {
4172 precision: None,
4173 scale: None
4174 })
4175 );
4176
4177 let min_type = annotator.get_aggregate_return_type("MIN", &[make_string_literal("a")]);
4179 assert_eq!(
4180 min_type,
4181 Some(DataType::VarChar {
4182 length: None,
4183 parenthesized_length: false
4184 })
4185 );
4186
4187 let top_n_type = annotator
4189 .get_aggregate_return_type("MAX", &[make_string_literal("a"), make_int_literal(2)]);
4190 assert_eq!(
4191 top_n_type,
4192 Some(DataType::Array {
4193 element_type: Box::new(DataType::VarChar {
4194 length: None,
4195 parenthesized_length: false,
4196 }),
4197 dimension: None,
4198 })
4199 );
4200 }
4201
4202 #[test]
4203 fn test_date_literal_types() {
4204 let mut annotator = TypeAnnotator::new(None, None);
4205
4206 let date_expr = Expression::Literal(Box::new(Literal::Date("2024-01-15".to_string())));
4208 assert_eq!(annotator.annotate(&date_expr), Some(DataType::Date));
4209
4210 let time_expr = Expression::Literal(Box::new(Literal::Time("10:30:00".to_string())));
4212 assert_eq!(
4213 annotator.annotate(&time_expr),
4214 Some(DataType::Time {
4215 precision: None,
4216 timezone: false
4217 })
4218 );
4219
4220 let ts_expr = Expression::Literal(Box::new(Literal::Timestamp(
4222 "2024-01-15 10:30:00".to_string(),
4223 )));
4224 assert_eq!(
4225 annotator.annotate(&ts_expr),
4226 Some(DataType::Timestamp {
4227 precision: None,
4228 timezone: false
4229 })
4230 );
4231 }
4232
4233 #[test]
4234 fn test_logical_operations() {
4235 let mut annotator = TypeAnnotator::new(None, None);
4236
4237 let and_expr = Expression::And(Box::new(BinaryOp::new(
4239 make_bool_literal(true),
4240 make_bool_literal(false),
4241 )));
4242 assert_eq!(annotator.annotate(&and_expr), Some(DataType::Boolean));
4243
4244 let or_expr = Expression::Or(Box::new(BinaryOp::new(
4246 make_bool_literal(true),
4247 make_bool_literal(false),
4248 )));
4249 assert_eq!(annotator.annotate(&or_expr), Some(DataType::Boolean));
4250
4251 let not_expr = Expression::Not(Box::new(crate::expressions::UnaryOp::new(
4253 make_bool_literal(true),
4254 )));
4255 assert_eq!(annotator.annotate(¬_expr), Some(DataType::Boolean));
4256 }
4257
4258 #[test]
4263 fn test_subscript_array_type() {
4264 let mut annotator = TypeAnnotator::new(None, None);
4265
4266 let arr = Expression::Array(Box::new(crate::expressions::Array {
4268 expressions: vec![make_int_literal(1), make_int_literal(2)],
4269 inferred_type: None,
4270 }));
4271 let subscript = Expression::Subscript(Box::new(crate::expressions::Subscript {
4272 this: arr,
4273 index: make_int_literal(0),
4274 }));
4275 assert_eq!(
4276 annotator.annotate(&subscript),
4277 Some(DataType::Int {
4278 length: None,
4279 integer_spelling: false
4280 })
4281 );
4282 }
4283
4284 #[test]
4285 fn test_subscript_map_type() {
4286 let mut annotator = TypeAnnotator::new(None, None);
4287
4288 let map = Expression::Map(Box::new(crate::expressions::Map {
4290 keys: vec![make_string_literal("a")],
4291 values: vec![make_int_literal(1)],
4292 }));
4293 let subscript = Expression::Subscript(Box::new(crate::expressions::Subscript {
4294 this: map,
4295 index: make_string_literal("a"),
4296 }));
4297 assert_eq!(
4298 annotator.annotate(&subscript),
4299 Some(DataType::Int {
4300 length: None,
4301 integer_spelling: false
4302 })
4303 );
4304 }
4305
4306 #[test]
4307 fn test_struct_type() {
4308 let mut annotator = TypeAnnotator::new(None, None);
4309
4310 let struct_expr = Expression::Struct(Box::new(crate::expressions::Struct {
4312 fields: vec![
4313 (Some("name".to_string()), make_string_literal("Alice")),
4314 (Some("age".to_string()), make_int_literal(30)),
4315 ],
4316 }));
4317 let result = annotator.annotate(&struct_expr);
4318 assert!(matches!(result, Some(DataType::Struct { fields, .. }) if fields.len() == 2));
4319 }
4320
4321 #[test]
4322 fn test_map_type() {
4323 let mut annotator = TypeAnnotator::new(None, None);
4324
4325 let map_expr = Expression::Map(Box::new(crate::expressions::Map {
4327 keys: vec![make_string_literal("a"), make_string_literal("b")],
4328 values: vec![make_int_literal(1), make_int_literal(2)],
4329 }));
4330 let result = annotator.annotate(&map_expr);
4331 assert!(matches!(
4332 result,
4333 Some(DataType::Map { key_type, value_type })
4334 if matches!(*key_type, DataType::VarChar { .. })
4335 && matches!(*value_type, DataType::Int { .. })
4336 ));
4337 }
4338
4339 #[test]
4340 fn test_explode_array_type() {
4341 let mut annotator = TypeAnnotator::new(None, None);
4342
4343 let arr = Expression::Array(Box::new(crate::expressions::Array {
4345 expressions: vec![make_int_literal(1), make_int_literal(2)],
4346 inferred_type: None,
4347 }));
4348 let explode = Expression::Explode(Box::new(crate::expressions::UnaryFunc {
4349 this: arr,
4350 original_name: None,
4351 inferred_type: None,
4352 }));
4353 assert_eq!(
4354 annotator.annotate(&explode),
4355 Some(DataType::Int {
4356 length: None,
4357 integer_spelling: false
4358 })
4359 );
4360 }
4361
4362 #[test]
4363 fn test_unnest_array_type() {
4364 let mut annotator = TypeAnnotator::new(None, None);
4365
4366 let arr = Expression::Array(Box::new(crate::expressions::Array {
4368 expressions: vec![make_string_literal("a"), make_string_literal("b")],
4369 inferred_type: None,
4370 }));
4371 let unnest = Expression::Unnest(Box::new(crate::expressions::UnnestFunc {
4372 this: arr,
4373 expressions: Vec::new(),
4374 with_ordinality: false,
4375 alias: None,
4376 offset_alias: None,
4377 inferred_type: None,
4378 }));
4379 assert_eq!(
4380 annotator.annotate(&unnest),
4381 Some(DataType::VarChar {
4382 length: None,
4383 parenthesized_length: false
4384 })
4385 );
4386 }
4387
4388 #[test]
4389 fn test_annotate_duckdb_array_case_unnest_types() {
4390 let timestamp = DataType::Timestamp {
4391 precision: None,
4392 timezone: false,
4393 };
4394 let array_timestamp = DataType::Array {
4395 element_type: Box::new(timestamp.clone()),
4396 dimension: None,
4397 };
4398 let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
4399 schema
4400 .add_table(
4401 "events",
4402 &[
4403 ("created_at".to_string(), timestamp.clone()),
4404 ("closed_at".to_string(), timestamp.clone()),
4405 ],
4406 None,
4407 )
4408 .unwrap();
4409
4410 let mut expr = parse_one(
4411 "SELECT UNNEST(CASE WHEN closed_at IS NULL THEN ARRAY[created_at] \
4412 ELSE ARRAY[created_at, closed_at] END) AS event_at FROM events",
4413 DialectType::DuckDB,
4414 )
4415 .unwrap();
4416 annotate_types(&mut expr, Some(&schema), Some(DialectType::DuckDB));
4417
4418 let Expression::Select(select) = &expr else {
4419 panic!("expected select");
4420 };
4421 let Expression::Alias(alias) = &select.expressions[0] else {
4422 panic!("expected alias");
4423 };
4424 let Expression::Function(unnest) = &alias.this else {
4425 panic!("expected UNNEST function");
4426 };
4427 assert_eq!(unnest.name, "UNNEST");
4428 let Expression::Case(case) = &unnest.args[0] else {
4429 panic!("expected case");
4430 };
4431 let Expression::ArrayFunc(then_array) = &case.whens[0].1 else {
4432 panic!("expected ARRAY constructor in THEN branch");
4433 };
4434 let Expression::ArrayFunc(else_array) = case.else_.as_ref().expect("expected ELSE") else {
4435 panic!("expected ARRAY constructor in ELSE branch");
4436 };
4437
4438 assert_eq!(then_array.inferred_type.as_ref(), Some(&array_timestamp));
4439 assert_eq!(else_array.inferred_type.as_ref(), Some(&array_timestamp));
4440 assert_eq!(case.inferred_type.as_ref(), Some(&array_timestamp));
4441 assert_eq!(unnest.inferred_type.as_ref(), Some(×tamp));
4442 assert_eq!(alias.inferred_type.as_ref(), Some(×tamp));
4443 assert!(then_array
4444 .expressions
4445 .iter()
4446 .all(|expression| { expression.inferred_type() == Some(×tamp) }));
4447 assert!(else_array
4448 .expressions
4449 .iter()
4450 .all(|expression| { expression.inferred_type() == Some(×tamp) }));
4451 }
4452
4453 #[test]
4454 fn test_array_and_case_coerce_all_result_types() {
4455 let mut expr = parse_one(
4456 "SELECT CASE WHEN TRUE THEN ARRAY[1] ELSE ARRAY[2.5] END AS values",
4457 DialectType::DuckDB,
4458 )
4459 .unwrap();
4460 annotate_types(&mut expr, None, Some(DialectType::DuckDB));
4461
4462 let Expression::Select(select) = &expr else {
4463 panic!("expected select");
4464 };
4465 let Expression::Alias(alias) = &select.expressions[0] else {
4466 panic!("expected alias");
4467 };
4468 assert_eq!(
4469 alias.this.inferred_type(),
4470 Some(&DataType::Array {
4471 element_type: Box::new(DataType::Double {
4472 precision: None,
4473 scale: None,
4474 }),
4475 dimension: None,
4476 })
4477 );
4478 }
4479
4480 #[test]
4481 fn test_transparent_wrappers_preserve_scalar_types() {
4482 let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
4483 schema
4484 .add_table("flags", &[("flag".to_string(), DataType::Boolean)], None)
4485 .unwrap();
4486 let varchar = DataType::VarChar {
4487 length: None,
4488 parenthesized_length: false,
4489 };
4490
4491 let mut parenthesized = parse_one(
4492 "SELECT (CASE WHEN flag THEN 'yes' ELSE 'no' END) AS label FROM flags",
4493 DialectType::DuckDB,
4494 )
4495 .unwrap();
4496 annotate_types(&mut parenthesized, Some(&schema), Some(DialectType::DuckDB));
4497
4498 let Expression::Select(select) = &parenthesized else {
4499 panic!("expected select");
4500 };
4501 let Expression::Alias(alias) = &select.expressions[0] else {
4502 panic!("expected alias");
4503 };
4504 let Expression::Paren(paren) = &alias.this else {
4505 panic!("expected parenthesized expression");
4506 };
4507 let Expression::Case(case) = &paren.this else {
4508 panic!("expected case");
4509 };
4510 let Expression::Column(column) = &case.whens[0].0 else {
4511 panic!("expected column condition");
4512 };
4513
4514 assert_eq!(alias.this.inferred_type(), Some(&varchar));
4515 assert_eq!(case.inferred_type.as_ref(), Some(&varchar));
4516 assert_eq!(column.inferred_type.as_ref(), Some(&DataType::Boolean));
4517 assert_eq!(alias.inferred_type.as_ref(), Some(&varchar));
4518
4519 let mut annotated = parse_one(
4520 "SELECT CASE WHEN flag THEN 'yes' ELSE 'no' END /*tail*/ FROM flags",
4521 DialectType::DuckDB,
4522 )
4523 .unwrap();
4524 annotate_types(&mut annotated, Some(&schema), Some(DialectType::DuckDB));
4525
4526 let Expression::Select(select) = &annotated else {
4527 panic!("expected select");
4528 };
4529 let Expression::Annotated(annotated) = &select.expressions[0] else {
4530 panic!("expected comment annotation wrapper");
4531 };
4532 let Expression::Case(case) = &annotated.this else {
4533 panic!("expected case");
4534 };
4535 let Expression::Column(column) = &case.whens[0].0 else {
4536 panic!("expected column condition");
4537 };
4538
4539 assert_eq!(select.expressions[0].inferred_type(), Some(&varchar));
4540 assert_eq!(case.inferred_type.as_ref(), Some(&varchar));
4541 assert_eq!(column.inferred_type.as_ref(), Some(&DataType::Boolean));
4542 }
4543
4544 #[test]
4545 fn test_set_operation_type() {
4546 let mut annotator = TypeAnnotator::new(None, None);
4547
4548 let select = Expression::Select(Box::new(crate::expressions::Select::default()));
4550 let union = Expression::Union(Box::new(crate::expressions::Union {
4551 left: select.clone(),
4552 right: select.clone(),
4553 all: false,
4554 distinct: false,
4555 with: None,
4556 order_by: None,
4557 limit: None,
4558 offset: None,
4559 by_name: false,
4560 side: None,
4561 kind: None,
4562 corresponding: false,
4563 strict: false,
4564 on_columns: Vec::new(),
4565 distribute_by: None,
4566 sort_by: None,
4567 cluster_by: None,
4568 }));
4569 assert_eq!(annotator.annotate(&union), None);
4570 }
4571
4572 #[test]
4573 fn test_floor_ceil_input_dependent_types() {
4574 use crate::expressions::{CeilFunc, FloorFunc};
4575
4576 let mut annotator = TypeAnnotator::new(None, None);
4577
4578 let floor_int = Expression::Floor(Box::new(FloorFunc {
4580 this: make_int_literal(42),
4581 scale: None,
4582 to: None,
4583 }));
4584 assert_eq!(
4585 annotator.annotate(&floor_int),
4586 Some(DataType::Double {
4587 precision: None,
4588 scale: None,
4589 })
4590 );
4591
4592 let ceil_int = Expression::Ceil(Box::new(CeilFunc {
4593 this: make_int_literal(42),
4594 decimals: None,
4595 to: None,
4596 }));
4597 assert_eq!(
4598 annotator.annotate(&ceil_int),
4599 Some(DataType::Double {
4600 precision: None,
4601 scale: None,
4602 })
4603 );
4604
4605 let floor_float = Expression::Floor(Box::new(FloorFunc {
4607 this: make_float_literal(3.14),
4608 scale: None,
4609 to: None,
4610 }));
4611 assert_eq!(
4612 annotator.annotate(&floor_float),
4613 Some(DataType::Double {
4614 precision: None,
4615 scale: None,
4616 })
4617 );
4618
4619 let floor_fn =
4621 Expression::Function(Box::new(Function::new("FLOOR", vec![make_int_literal(1)])));
4622 assert_eq!(
4623 annotator.annotate(&floor_fn),
4624 Some(DataType::Int {
4625 length: None,
4626 integer_spelling: false,
4627 })
4628 );
4629 }
4630
4631 #[test]
4632 fn test_sign_preserves_input_type() {
4633 use crate::expressions::UnaryFunc;
4634
4635 let mut annotator = TypeAnnotator::new(None, None);
4636
4637 let sign_int = Expression::Sign(Box::new(UnaryFunc {
4639 this: make_int_literal(42),
4640 original_name: None,
4641 inferred_type: None,
4642 }));
4643 assert_eq!(
4644 annotator.annotate(&sign_int),
4645 Some(DataType::Int {
4646 length: None,
4647 integer_spelling: false,
4648 })
4649 );
4650
4651 let sign_float = Expression::Sign(Box::new(UnaryFunc {
4653 this: make_float_literal(3.14),
4654 original_name: None,
4655 inferred_type: None,
4656 }));
4657 assert_eq!(
4658 annotator.annotate(&sign_float),
4659 Some(DataType::Double {
4660 precision: None,
4661 scale: None,
4662 })
4663 );
4664
4665 let sign_cast = Expression::Sign(Box::new(UnaryFunc {
4667 this: Expression::Cast(Box::new(Cast {
4668 this: make_int_literal(42),
4669 to: DataType::Int {
4670 length: None,
4671 integer_spelling: false,
4672 },
4673 format: None,
4674 trailing_comments: Vec::new(),
4675 double_colon_syntax: false,
4676 default: None,
4677 inferred_type: None,
4678 })),
4679 original_name: None,
4680 inferred_type: None,
4681 }));
4682 assert_eq!(
4683 annotator.annotate(&sign_cast),
4684 Some(DataType::Int {
4685 length: None,
4686 integer_spelling: false,
4687 })
4688 );
4689 }
4690
4691 #[test]
4692 fn test_date_format_types() {
4693 use crate::expressions::{DateFormatFunc, TimeToStr};
4694
4695 let mut annotator = TypeAnnotator::new(None, None);
4696
4697 let date_fmt = Expression::DateFormat(Box::new(DateFormatFunc {
4699 this: make_string_literal("2024-01-01"),
4700 format: make_string_literal("%Y-%m-%d"),
4701 }));
4702 assert_eq!(
4703 annotator.annotate(&date_fmt),
4704 Some(DataType::VarChar {
4705 length: None,
4706 parenthesized_length: false,
4707 })
4708 );
4709
4710 let format_date = Expression::FormatDate(Box::new(DateFormatFunc {
4712 this: make_string_literal("2024-01-01"),
4713 format: make_string_literal("%Y-%m-%d"),
4714 }));
4715 assert_eq!(
4716 annotator.annotate(&format_date),
4717 Some(DataType::VarChar {
4718 length: None,
4719 parenthesized_length: false,
4720 })
4721 );
4722
4723 let time_to_str = Expression::TimeToStr(Box::new(TimeToStr {
4725 this: Box::new(make_string_literal("2024-01-01")),
4726 format: "%Y-%m-%d".to_string(),
4727 culture: None,
4728 zone: None,
4729 }));
4730 assert_eq!(
4731 annotator.annotate(&time_to_str),
4732 Some(DataType::VarChar {
4733 length: None,
4734 parenthesized_length: false,
4735 })
4736 );
4737
4738 let date_fmt_fn = Expression::Function(Box::new(Function::new(
4740 "DATE_FORMAT",
4741 vec![
4742 make_string_literal("2024-01-01"),
4743 make_string_literal("%Y-%m-%d"),
4744 ],
4745 )));
4746 assert_eq!(
4747 annotator.annotate(&date_fmt_fn),
4748 Some(DataType::VarChar {
4749 length: None,
4750 parenthesized_length: false,
4751 })
4752 );
4753 }
4754
4755 #[test]
4758 fn test_annotate_in_place_sets_type_on_root() {
4759 let mut expr = Expression::Add(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!(
4766 expr.inferred_type(),
4767 Some(&DataType::Int {
4768 length: None,
4769 integer_spelling: false,
4770 })
4771 );
4772 }
4773
4774 #[test]
4775 fn test_annotate_in_place_sets_types_on_children() {
4776 let inner_add = Expression::Add(Box::new(BinaryOp::new(
4779 make_int_literal(1),
4780 make_float_literal(2.5),
4781 )));
4782 let inner_sub = Expression::Sub(Box::new(BinaryOp::new(
4783 make_int_literal(3),
4784 make_int_literal(4),
4785 )));
4786 let mut expr = Expression::Add(Box::new(BinaryOp::new(inner_add, inner_sub)));
4787 annotate_types(&mut expr, None, None);
4788
4789 assert_eq!(
4791 expr.inferred_type(),
4792 Some(&DataType::Double {
4793 precision: None,
4794 scale: None,
4795 })
4796 );
4797
4798 if let Expression::Add(op) = &expr {
4800 assert_eq!(
4802 op.left.inferred_type(),
4803 Some(&DataType::Double {
4804 precision: None,
4805 scale: None,
4806 })
4807 );
4808 assert_eq!(
4810 op.right.inferred_type(),
4811 Some(&DataType::Int {
4812 length: None,
4813 integer_spelling: false,
4814 })
4815 );
4816 } else {
4817 panic!("Expected Add expression");
4818 }
4819 }
4820
4821 #[test]
4822 fn test_annotate_in_place_comparison() {
4823 let mut expr = Expression::Eq(Box::new(BinaryOp::new(
4824 make_int_literal(1),
4825 make_int_literal(2),
4826 )));
4827 annotate_types(&mut expr, None, None);
4828 assert_eq!(expr.inferred_type(), Some(&DataType::Boolean));
4829 }
4830
4831 #[test]
4832 fn test_annotate_in_place_cast() {
4833 let mut expr = Expression::Cast(Box::new(Cast {
4834 this: make_int_literal(42),
4835 to: DataType::VarChar {
4836 length: None,
4837 parenthesized_length: false,
4838 },
4839 trailing_comments: vec![],
4840 double_colon_syntax: false,
4841 format: None,
4842 default: None,
4843 inferred_type: None,
4844 }));
4845 annotate_types(&mut expr, None, None);
4846 assert_eq!(
4847 expr.inferred_type(),
4848 Some(&DataType::VarChar {
4849 length: None,
4850 parenthesized_length: false,
4851 })
4852 );
4853 }
4854
4855 #[test]
4856 fn test_annotate_in_place_nested_expression() {
4857 let add = Expression::Add(Box::new(BinaryOp::new(
4859 make_int_literal(1),
4860 make_int_literal(2),
4861 )));
4862 let mut expr = Expression::Gt(Box::new(BinaryOp::new(add, make_int_literal(0))));
4863 annotate_types(&mut expr, None, None);
4864
4865 assert_eq!(expr.inferred_type(), Some(&DataType::Boolean));
4866
4867 if let Expression::Gt(op) = &expr {
4869 assert_eq!(
4870 op.left.inferred_type(),
4871 Some(&DataType::Int {
4872 length: None,
4873 integer_spelling: false,
4874 })
4875 );
4876 }
4877 }
4878
4879 #[test]
4880 fn test_annotate_in_place_parsed_sql() {
4881 use crate::parser::Parser;
4882 let mut expr =
4883 Parser::parse_sql("SELECT 1 + 2.0, 'hello', TRUE").expect("parse failed")[0].clone();
4884 annotate_types(&mut expr, None, None);
4885
4886 assert!(expr.inferred_type().is_none());
4890 }
4891
4892 #[test]
4893 fn test_inferred_type_json_roundtrip() {
4894 let mut expr = Expression::Add(Box::new(BinaryOp::new(
4895 make_int_literal(1),
4896 make_int_literal(2),
4897 )));
4898 annotate_types(&mut expr, None, None);
4899
4900 let json = serde_json::to_string(&expr).expect("serialize failed");
4902 assert!(json.contains("inferred_type"));
4904
4905 let deserialized: Expression = serde_json::from_str(&json).expect("deserialize failed");
4907 assert_eq!(
4908 deserialized.inferred_type(),
4909 Some(&DataType::Int {
4910 length: None,
4911 integer_spelling: false,
4912 })
4913 );
4914 }
4915
4916 #[test]
4917 fn test_inferred_type_none_not_serialized() {
4918 let expr = Expression::Add(Box::new(BinaryOp::new(
4920 make_int_literal(1),
4921 make_int_literal(2),
4922 )));
4923 let json = serde_json::to_string(&expr).expect("serialize failed");
4924 assert!(!json.contains("inferred_type"));
4925 }
4926
4927 #[test]
4928 fn test_annotate_if_func_bigquery_node_and_alias_type() {
4929 let mut schema = MappingSchema::with_dialect(DialectType::BigQuery);
4930 schema
4931 .add_table(
4932 "t",
4933 &[("col1".to_string(), DataType::String { length: None })],
4934 None,
4935 )
4936 .unwrap();
4937
4938 let mut expr = parse_one(
4939 "SELECT IF(col1 IS NOT NULL, 1, 0) AS x FROM t",
4940 DialectType::BigQuery,
4941 )
4942 .unwrap();
4943 annotate_types(&mut expr, Some(&schema), Some(DialectType::BigQuery));
4944
4945 let Expression::Select(select) = &expr else {
4946 panic!("expected select");
4947 };
4948 let Expression::Alias(alias) = &select.expressions[0] else {
4949 panic!("expected alias");
4950 };
4951
4952 assert_eq!(
4953 alias.this.inferred_type(),
4954 Some(&DataType::Int {
4955 length: None,
4956 integer_spelling: false,
4957 })
4958 );
4959 assert_eq!(
4960 select.expressions[0].inferred_type(),
4961 Some(&DataType::Int {
4962 length: None,
4963 integer_spelling: false,
4964 })
4965 );
4966 }
4967
4968 #[test]
4969 fn test_annotate_nvl2_node_type() {
4970 let mut expr = parse_one("SELECT NVL2(a, 1, 0) AS x", DialectType::Generic).unwrap();
4971 annotate_types(&mut expr, None, None);
4972
4973 let Expression::Select(select) = &expr else {
4974 panic!("expected select");
4975 };
4976 let Expression::Alias(alias) = &select.expressions[0] else {
4977 panic!("expected alias");
4978 };
4979
4980 assert_eq!(
4981 alias.this.inferred_type(),
4982 Some(&DataType::Int {
4983 length: None,
4984 integer_spelling: false,
4985 })
4986 );
4987 }
4988
4989 #[test]
4990 fn test_annotate_count_node_type() {
4991 let mut expr = parse_one("SELECT COUNT(1) AS x", DialectType::Generic).unwrap();
4992 annotate_types(&mut expr, None, None);
4993
4994 let Expression::Select(select) = &expr else {
4995 panic!("expected select");
4996 };
4997 let Expression::Alias(alias) = &select.expressions[0] else {
4998 panic!("expected alias");
4999 };
5000
5001 assert_eq!(
5002 alias.this.inferred_type(),
5003 Some(&DataType::BigInt { length: None })
5004 );
5005 }
5006
5007 #[test]
5008 fn test_annotate_group_concat_node_type() {
5009 let mut expr = parse_one("SELECT GROUP_CONCAT(a) AS x", DialectType::Generic).unwrap();
5010 annotate_types(&mut expr, None, None);
5011
5012 let Expression::Select(select) = &expr else {
5013 panic!("expected select");
5014 };
5015 let Expression::Alias(alias) = &select.expressions[0] else {
5016 panic!("expected alias");
5017 };
5018
5019 assert_eq!(
5020 alias.this.inferred_type(),
5021 Some(&DataType::VarChar {
5022 length: None,
5023 parenthesized_length: false,
5024 })
5025 );
5026 }
5027
5028 #[test]
5029 fn test_annotate_sum_if_generic_aggregate_type() {
5030 let mut expr =
5031 parse_one("SELECT SUM_IF(1, a > 0) AS x FROM t", DialectType::Generic).unwrap();
5032 annotate_types(&mut expr, None, None);
5033
5034 let Expression::Select(select) = &expr else {
5035 panic!("expected select");
5036 };
5037 let Expression::Alias(alias) = &select.expressions[0] else {
5038 panic!("expected alias");
5039 };
5040
5041 assert_eq!(
5042 select.expressions[0].inferred_type(),
5043 Some(&DataType::BigInt { length: None })
5044 );
5045 assert_eq!(
5046 alias.this.inferred_type(),
5047 Some(&DataType::BigInt { length: None })
5048 );
5049 }
5050
5051 #[test]
5052 fn test_annotate_duckdb_median_node_types() {
5053 let cases = [
5054 (
5055 "SELECT MEDIAN(CAST(1 AS INTEGER)) AS result",
5056 DataType::Double {
5057 precision: None,
5058 scale: None,
5059 },
5060 ),
5061 (
5062 "SELECT MEDIAN(CAST(1 AS FLOAT)) AS result",
5063 DataType::Float {
5064 precision: None,
5065 scale: None,
5066 real_spelling: false,
5067 },
5068 ),
5069 (
5070 "SELECT MEDIAN(CAST(1 AS DECIMAL(10, 2))) AS result",
5071 DataType::Decimal {
5072 precision: Some(10),
5073 scale: Some(2),
5074 },
5075 ),
5076 (
5077 "SELECT MEDIAN(CAST('2024-01-01' AS DATE)) AS result",
5078 DataType::Timestamp {
5079 precision: None,
5080 timezone: false,
5081 },
5082 ),
5083 ];
5084
5085 for (sql, expected) in cases {
5086 let mut expr = parse_one(sql, DialectType::DuckDB).unwrap();
5087 annotate_types(&mut expr, None, Some(DialectType::DuckDB));
5088
5089 let Expression::Select(select) = &expr else {
5090 panic!("expected select for {sql}");
5091 };
5092 let Expression::Alias(alias) = &select.expressions[0] else {
5093 panic!("expected alias for {sql}");
5094 };
5095
5096 assert_eq!(alias.this.inferred_type(), Some(&expected), "{sql}");
5097 assert_eq!(
5098 select.expressions[0].inferred_type(),
5099 Some(&expected),
5100 "{sql}"
5101 );
5102 }
5103 }
5104}