Skip to main content

polyglot_sql/optimizer/
annotate_types.rs

1//! Type Annotation for SQL Expressions
2//!
3//! This module provides type inference and annotation for SQL AST nodes.
4//! It walks the expression tree and assigns data types to expressions based on:
5//! - Literal values (strings, numbers, booleans)
6//! - Column references (from schema)
7//! - Function return types
8//! - Operator result types (with coercion rules)
9//!
10//! Based on SQLGlot's optimizer/annotate_types.py
11
12use std::collections::{HashMap, HashSet};
13
14use crate::dialects::DialectType;
15use crate::expressions::{
16    BinaryOp, DataType, DotAccess, Expression, Function, IfFunc, ListAggOverflow, Literal, Map,
17    Nvl2Func, Struct, StructField, Subscript,
18};
19use crate::schema::{normalize_name, Schema, SchemaError, SchemaResult, TABLE_PARTS};
20
21/// Type coercion class for determining result types in binary operations.
22/// Higher-priority classes win during coercion.
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
24pub enum TypeCoercionClass {
25    /// Text types (CHAR, VARCHAR, TEXT)
26    Text = 0,
27    /// Numeric types (INT, FLOAT, DECIMAL, etc.)
28    Numeric = 1,
29    /// Time-like types (DATE, TIME, TIMESTAMP, INTERVAL)
30    Timelike = 2,
31}
32
33impl TypeCoercionClass {
34    /// Get the coercion class for a data type
35    pub fn from_data_type(dt: &DataType) -> Option<Self> {
36        match dt {
37            // Text types
38            DataType::Char { .. }
39            | DataType::VarChar { .. }
40            | DataType::Text
41            | DataType::Binary { .. }
42            | DataType::VarBinary { .. }
43            | DataType::Blob => Some(TypeCoercionClass::Text),
44
45            // Numeric types
46            DataType::Boolean
47            | DataType::TinyInt { .. }
48            | DataType::SmallInt { .. }
49            | DataType::Int { .. }
50            | DataType::BigInt { .. }
51            | DataType::Float { .. }
52            | DataType::Double { .. }
53            | DataType::Decimal { .. } => Some(TypeCoercionClass::Numeric),
54
55            // Timelike types
56            DataType::Date
57            | DataType::Time { .. }
58            | DataType::Timestamp { .. }
59            | DataType::Interval { .. } => Some(TypeCoercionClass::Timelike),
60
61            // Other types don't have a coercion class
62            _ => None,
63        }
64    }
65}
66
67/// Type annotation configuration and state
68pub struct TypeAnnotator<'a> {
69    /// Schema for looking up column types
70    _schema: Option<&'a dyn Schema>,
71    /// Dialect for dialect-specific type rules
72    _dialect: Option<DialectType>,
73    /// Whether to annotate types for all expressions
74    annotate_aggregates: bool,
75    /// Function return type mappings
76    function_return_types: HashMap<String, DataType>,
77}
78
79impl<'a> TypeAnnotator<'a> {
80    /// Create a new type annotator
81    pub fn new(schema: Option<&'a dyn Schema>, dialect: Option<DialectType>) -> Self {
82        let mut annotator = Self {
83            _schema: schema,
84            _dialect: dialect,
85            annotate_aggregates: true,
86            function_return_types: HashMap::new(),
87        };
88        annotator.init_function_return_types();
89        annotator
90    }
91
92    /// Initialize function return type mappings
93    fn init_function_return_types(&mut self) {
94        // Aggregate functions
95        self.function_return_types
96            .insert("COUNT".to_string(), DataType::BigInt { length: None });
97        self.function_return_types.insert(
98            "SUM".to_string(),
99            DataType::Decimal {
100                precision: None,
101                scale: None,
102            },
103        );
104        self.function_return_types.insert(
105            "AVG".to_string(),
106            DataType::Double {
107                precision: None,
108                scale: None,
109            },
110        );
111
112        // String functions
113        self.function_return_types.insert(
114            "CONCAT".to_string(),
115            DataType::VarChar {
116                length: None,
117                parenthesized_length: false,
118            },
119        );
120        self.function_return_types.insert(
121            "UPPER".to_string(),
122            DataType::VarChar {
123                length: None,
124                parenthesized_length: false,
125            },
126        );
127        self.function_return_types.insert(
128            "LOWER".to_string(),
129            DataType::VarChar {
130                length: None,
131                parenthesized_length: false,
132            },
133        );
134        self.function_return_types.insert(
135            "TRIM".to_string(),
136            DataType::VarChar {
137                length: None,
138                parenthesized_length: false,
139            },
140        );
141        self.function_return_types.insert(
142            "LTRIM".to_string(),
143            DataType::VarChar {
144                length: None,
145                parenthesized_length: false,
146            },
147        );
148        self.function_return_types.insert(
149            "RTRIM".to_string(),
150            DataType::VarChar {
151                length: None,
152                parenthesized_length: false,
153            },
154        );
155        self.function_return_types.insert(
156            "SUBSTRING".to_string(),
157            DataType::VarChar {
158                length: None,
159                parenthesized_length: false,
160            },
161        );
162        self.function_return_types.insert(
163            "SUBSTR".to_string(),
164            DataType::VarChar {
165                length: None,
166                parenthesized_length: false,
167            },
168        );
169        self.function_return_types.insert(
170            "REPLACE".to_string(),
171            DataType::VarChar {
172                length: None,
173                parenthesized_length: false,
174            },
175        );
176        self.function_return_types.insert(
177            "LENGTH".to_string(),
178            DataType::Int {
179                length: None,
180                integer_spelling: false,
181            },
182        );
183        self.function_return_types.insert(
184            "CHAR_LENGTH".to_string(),
185            DataType::Int {
186                length: None,
187                integer_spelling: false,
188            },
189        );
190
191        // Date/Time functions
192        self.function_return_types.insert(
193            "NOW".to_string(),
194            DataType::Timestamp {
195                precision: None,
196                timezone: false,
197            },
198        );
199        self.function_return_types.insert(
200            "CURRENT_TIMESTAMP".to_string(),
201            DataType::Timestamp {
202                precision: None,
203                timezone: false,
204            },
205        );
206        self.function_return_types
207            .insert("CURRENT_DATE".to_string(), DataType::Date);
208        self.function_return_types.insert(
209            "CURRENT_TIME".to_string(),
210            DataType::Time {
211                precision: None,
212                timezone: false,
213            },
214        );
215        self.function_return_types
216            .insert("DATE".to_string(), DataType::Date);
217        self.function_return_types.insert(
218            "YEAR".to_string(),
219            DataType::Int {
220                length: None,
221                integer_spelling: false,
222            },
223        );
224        self.function_return_types.insert(
225            "MONTH".to_string(),
226            DataType::Int {
227                length: None,
228                integer_spelling: false,
229            },
230        );
231        self.function_return_types.insert(
232            "DAY".to_string(),
233            DataType::Int {
234                length: None,
235                integer_spelling: false,
236            },
237        );
238        self.function_return_types.insert(
239            "HOUR".to_string(),
240            DataType::Int {
241                length: None,
242                integer_spelling: false,
243            },
244        );
245        self.function_return_types.insert(
246            "MINUTE".to_string(),
247            DataType::Int {
248                length: None,
249                integer_spelling: false,
250            },
251        );
252        self.function_return_types.insert(
253            "SECOND".to_string(),
254            DataType::Int {
255                length: None,
256                integer_spelling: false,
257            },
258        );
259        self.function_return_types.insert(
260            "EXTRACT".to_string(),
261            DataType::Int {
262                length: None,
263                integer_spelling: false,
264            },
265        );
266        self.function_return_types.insert(
267            "DATE_DIFF".to_string(),
268            DataType::Int {
269                length: None,
270                integer_spelling: false,
271            },
272        );
273        self.function_return_types.insert(
274            "DATEDIFF".to_string(),
275            DataType::Int {
276                length: None,
277                integer_spelling: false,
278            },
279        );
280
281        // Math functions
282        self.function_return_types.insert(
283            "ABS".to_string(),
284            DataType::Double {
285                precision: None,
286                scale: None,
287            },
288        );
289        self.function_return_types.insert(
290            "ROUND".to_string(),
291            DataType::Double {
292                precision: None,
293                scale: None,
294            },
295        );
296        self.function_return_types.insert(
297            "DATE_FORMAT".to_string(),
298            DataType::VarChar {
299                length: None,
300                parenthesized_length: false,
301            },
302        );
303        self.function_return_types.insert(
304            "FORMAT_DATE".to_string(),
305            DataType::VarChar {
306                length: None,
307                parenthesized_length: false,
308            },
309        );
310        self.function_return_types.insert(
311            "TIME_TO_STR".to_string(),
312            DataType::VarChar {
313                length: None,
314                parenthesized_length: false,
315            },
316        );
317        self.function_return_types.insert(
318            "SQRT".to_string(),
319            DataType::Double {
320                precision: None,
321                scale: None,
322            },
323        );
324        self.function_return_types.insert(
325            "POWER".to_string(),
326            DataType::Double {
327                precision: None,
328                scale: None,
329            },
330        );
331        self.function_return_types.insert(
332            "MOD".to_string(),
333            DataType::Int {
334                length: None,
335                integer_spelling: false,
336            },
337        );
338        self.function_return_types.insert(
339            "LOG".to_string(),
340            DataType::Double {
341                precision: None,
342                scale: None,
343            },
344        );
345        self.function_return_types.insert(
346            "LN".to_string(),
347            DataType::Double {
348                precision: None,
349                scale: None,
350            },
351        );
352        self.function_return_types.insert(
353            "EXP".to_string(),
354            DataType::Double {
355                precision: None,
356                scale: None,
357            },
358        );
359
360        // Null-handling functions return Unknown (infer from args)
361        self.function_return_types
362            .insert("COALESCE".to_string(), DataType::Unknown);
363        self.function_return_types
364            .insert("NULLIF".to_string(), DataType::Unknown);
365        self.function_return_types
366            .insert("GREATEST".to_string(), DataType::Unknown);
367        self.function_return_types
368            .insert("LEAST".to_string(), DataType::Unknown);
369    }
370
371    /// Annotate types for an expression tree
372    pub fn annotate(&mut self, expr: &Expression) -> Option<DataType> {
373        match expr {
374            // Literals
375            Expression::Literal(lit) => self.annotate_literal(lit),
376            Expression::Boolean(_) => Some(DataType::Boolean),
377            Expression::Null(_) => None, // NULL has no type
378
379            // Arithmetic binary operations
380            Expression::Add(op)
381            | Expression::Sub(op)
382            | Expression::Mul(op)
383            | Expression::Div(op)
384            | Expression::Mod(op) => self.annotate_arithmetic(op),
385
386            // Comparison operations - always boolean
387            Expression::Eq(_)
388            | Expression::Neq(_)
389            | Expression::Lt(_)
390            | Expression::Lte(_)
391            | Expression::Gt(_)
392            | Expression::Gte(_)
393            | Expression::Like(_)
394            | Expression::ILike(_) => Some(DataType::Boolean),
395
396            // Logical operations - always boolean
397            Expression::And(_) | Expression::Or(_) | Expression::Not(_) => Some(DataType::Boolean),
398
399            // Predicates - always boolean
400            Expression::Between(_)
401            | Expression::In(_)
402            | Expression::IsNull(_)
403            | Expression::IsTrue(_)
404            | Expression::IsFalse(_)
405            | Expression::Is(_)
406            | Expression::Exists(_) => Some(DataType::Boolean),
407
408            // String concatenation
409            Expression::Concat(_) => Some(DataType::VarChar {
410                length: None,
411                parenthesized_length: false,
412            }),
413
414            // Bitwise operations - integer
415            Expression::BitwiseAnd(_)
416            | Expression::BitwiseOr(_)
417            | Expression::BitwiseXor(_)
418            | Expression::BitwiseNot(_) => Some(DataType::BigInt { length: None }),
419
420            // Negation preserves type
421            Expression::Neg(op) => self.annotate(&op.this),
422
423            // Functions
424            Expression::Function(func) => self.annotate_function(func),
425            Expression::IfFunc(if_func) => self.annotate_if_func(if_func),
426            Expression::Nvl2(nvl2) => self.annotate_nvl2(nvl2),
427            Expression::Coalesce(coalesce) => self.coerce_arg_types(&coalesce.expressions),
428
429            // Typed aggregate functions
430            Expression::Count(_) => Some(DataType::BigInt { length: None }),
431            Expression::Sum(agg) => self.annotate_sum(&agg.this),
432            Expression::SumIf(f) => self.annotate_sum(&f.this),
433            Expression::Avg(_) => Some(DataType::Double {
434                precision: None,
435                scale: None,
436            }),
437            Expression::Min(agg) => self.annotate(&agg.this),
438            Expression::Max(agg) => self.annotate(&agg.this),
439            Expression::GroupConcat(_) | Expression::StringAgg(_) | Expression::ListAgg(_) => {
440                Some(DataType::VarChar {
441                    length: None,
442                    parenthesized_length: false,
443                })
444            }
445
446            // Generic aggregate function
447            Expression::AggregateFunction(agg) => {
448                if !self.annotate_aggregates {
449                    return None;
450                }
451                let func_name = agg.name.to_uppercase();
452                self.get_aggregate_return_type(&func_name, &agg.args)
453            }
454
455            // Column references - look up type from schema if available
456            Expression::Column(col) => {
457                if let Some(schema) = &self._schema {
458                    let table_name = col.table.as_ref().map(|t| t.name.as_str()).unwrap_or("");
459                    schema.get_column_type(table_name, &col.name.name).ok()
460                } else {
461                    None
462                }
463            }
464
465            // Cast expressions
466            Expression::Cast(cast) => Some(cast.to.clone()),
467            Expression::SafeCast(cast) => Some(cast.to.clone()),
468            Expression::TryCast(cast) => Some(cast.to.clone()),
469
470            // Subqueries - type is the type of the first SELECT expression
471            Expression::Subquery(subq) => {
472                if let Expression::Select(select) = &subq.this {
473                    if let Some(first) = select.expressions.first() {
474                        self.annotate(first)
475                    } else {
476                        None
477                    }
478                } else {
479                    None
480                }
481            }
482
483            // CASE expression - type of the first THEN/ELSE
484            Expression::Case(case) => {
485                if let Some(else_expr) = &case.else_ {
486                    self.annotate(else_expr)
487                } else if let Some((_, then_expr)) = case.whens.first() {
488                    self.annotate(then_expr)
489                } else {
490                    None
491                }
492            }
493
494            // Array expressions
495            Expression::Array(arr) => {
496                if let Some(first) = arr.expressions.first() {
497                    if let Some(elem_type) = self.annotate(first) {
498                        Some(DataType::Array {
499                            element_type: Box::new(elem_type),
500                            dimension: None,
501                        })
502                    } else {
503                        Some(DataType::Array {
504                            element_type: Box::new(DataType::Unknown),
505                            dimension: None,
506                        })
507                    }
508                } else {
509                    Some(DataType::Array {
510                        element_type: Box::new(DataType::Unknown),
511                        dimension: None,
512                    })
513                }
514            }
515
516            // Interval expressions
517            Expression::Interval(_) => Some(DataType::Interval {
518                unit: None,
519                to: None,
520            }),
521
522            // Window functions inherit type from their function
523            Expression::WindowFunction(window) => self.annotate(&window.this),
524
525            // Date/time expressions
526            Expression::CurrentDate(_) => Some(DataType::Date),
527            Expression::CurrentTime(_) => Some(DataType::Time {
528                precision: None,
529                timezone: false,
530            }),
531            Expression::CurrentTimestamp(_) | Expression::CurrentTimestampLTZ(_) => {
532                Some(DataType::Timestamp {
533                    precision: None,
534                    timezone: false,
535                })
536            }
537
538            // Date functions
539            Expression::DateAdd(_)
540            | Expression::DateSub(_)
541            | Expression::ToDate(_)
542            | Expression::Date(_) => Some(DataType::Date),
543            Expression::DateDiff(_) | Expression::Extract(_) => Some(DataType::Int {
544                length: None,
545                integer_spelling: false,
546            }),
547            Expression::ToTimestamp(_) => Some(DataType::Timestamp {
548                precision: None,
549                timezone: false,
550            }),
551
552            // String functions
553            Expression::Upper(_)
554            | Expression::Lower(_)
555            | Expression::Trim(_)
556            | Expression::LTrim(_)
557            | Expression::RTrim(_)
558            | Expression::Replace(_)
559            | Expression::Substring(_)
560            | Expression::Reverse(_)
561            | Expression::Left(_)
562            | Expression::Right(_)
563            | Expression::Repeat(_)
564            | Expression::Lpad(_)
565            | Expression::Rpad(_)
566            | Expression::ConcatWs(_)
567            | Expression::Overlay(_) => Some(DataType::VarChar {
568                length: None,
569                parenthesized_length: false,
570            }),
571            Expression::Length(_) => Some(DataType::Int {
572                length: None,
573                integer_spelling: false,
574            }),
575
576            // Math functions
577            Expression::Abs(_)
578            | Expression::Sqrt(_)
579            | Expression::Cbrt(_)
580            | Expression::Ln(_)
581            | Expression::Exp(_)
582            | Expression::Power(_)
583            | Expression::Log(_) => Some(DataType::Double {
584                precision: None,
585                scale: None,
586            }),
587            Expression::Round(_) => Some(DataType::Double {
588                precision: None,
589                scale: None,
590            }),
591            Expression::Floor(f) => self.annotate_math_function(&f.this),
592            Expression::Ceil(f) => self.annotate_math_function(&f.this),
593            Expression::Sign(s) => self.annotate(&s.this),
594            Expression::DateFormat(_) | Expression::FormatDate(_) | Expression::TimeToStr(_) => {
595                Some(DataType::VarChar {
596                    length: None,
597                    parenthesized_length: false,
598                })
599            }
600
601            // Greatest/Least - coerce argument types
602            Expression::Greatest(v) | Expression::Least(v) => self.coerce_arg_types(&v.expressions),
603
604            // Alias - type of the inner expression
605            Expression::Alias(alias) => self.annotate(&alias.this),
606
607            // SELECT expressions - no scalar type
608            Expression::Select(_) => None,
609
610            // ============================================
611            // 3.1.8: Array/Map Indexing (Subscript/Bracket)
612            // ============================================
613            Expression::Subscript(sub) => self.annotate_subscript(sub),
614
615            // Dot access (struct.field) - resolve the field from the base STRUCT type
616            Expression::Dot(dot) => self.annotate_dot(dot),
617
618            // ============================================
619            // 3.1.9: STRUCT Construction
620            // ============================================
621            Expression::Struct(s) => self.annotate_struct(s),
622
623            // ============================================
624            // 3.1.10: MAP Construction
625            // ============================================
626            Expression::Map(map) => self.annotate_map(map),
627            Expression::MapFromEntries(mfe) => {
628                // MAP_FROM_ENTRIES(array_of_pairs) - infer from array element type
629                if let Some(DataType::Array { element_type, .. }) = self.annotate(&mfe.this) {
630                    if let DataType::Struct { fields, .. } = *element_type {
631                        if fields.len() >= 2 {
632                            return Some(DataType::Map {
633                                key_type: Box::new(fields[0].data_type.clone()),
634                                value_type: Box::new(fields[1].data_type.clone()),
635                            });
636                        }
637                    }
638                }
639                Some(DataType::Map {
640                    key_type: Box::new(DataType::Unknown),
641                    value_type: Box::new(DataType::Unknown),
642                })
643            }
644
645            // ============================================
646            // 3.1.11: SetOperation Type Coercion
647            // ============================================
648            Expression::Union(union) => self.annotate_set_operation(&union.left, &union.right),
649            Expression::Intersect(intersect) => {
650                self.annotate_set_operation(&intersect.left, &intersect.right)
651            }
652            Expression::Except(except) => self.annotate_set_operation(&except.left, &except.right),
653
654            // ============================================
655            // 3.1.12: UDTF Type Handling
656            // ============================================
657            Expression::Lateral(lateral) => {
658                // LATERAL subquery - type is the subquery's type
659                self.annotate(&lateral.this)
660            }
661            Expression::LateralView(lv) => {
662                // LATERAL VIEW - returns the exploded type
663                self.annotate_lateral_view(lv)
664            }
665            Expression::Unnest(unnest) => {
666                // UNNEST(array) - returns the element type of the array
667                if let Some(DataType::Array { element_type, .. }) = self.annotate(&unnest.this) {
668                    Some(*element_type)
669                } else {
670                    None
671                }
672            }
673            Expression::Explode(explode) => {
674                // EXPLODE(array) - returns the element type
675                if let Some(DataType::Array { element_type, .. }) = self.annotate(&explode.this) {
676                    Some(*element_type)
677                } else if let Some(DataType::Map {
678                    key_type,
679                    value_type,
680                }) = self.annotate(&explode.this)
681                {
682                    // EXPLODE(map) returns struct(key, value)
683                    Some(DataType::Struct {
684                        fields: vec![
685                            StructField::new("key".to_string(), *key_type),
686                            StructField::new("value".to_string(), *value_type),
687                        ],
688                        nested: false,
689                    })
690                } else {
691                    None
692                }
693            }
694            Expression::ExplodeOuter(explode) => {
695                // EXPLODE_OUTER - same as EXPLODE but preserves nulls
696                if let Some(DataType::Array { element_type, .. }) = self.annotate(&explode.this) {
697                    Some(*element_type)
698                } else {
699                    None
700                }
701            }
702            Expression::GenerateSeries(gs) => {
703                // GENERATE_SERIES returns the type of start/end
704                if let Some(ref start) = gs.start {
705                    self.annotate(start)
706                } else if let Some(ref end) = gs.end {
707                    self.annotate(end)
708                } else {
709                    Some(DataType::Int {
710                        length: None,
711                        integer_spelling: false,
712                    })
713                }
714            }
715
716            // Other expressions - unknown
717            _ => None,
718        }
719    }
720
721    /// Annotate types in-place on the expression tree (bottom-up).
722    ///
723    /// First recurses into children, then computes this node's type using the
724    /// read-only `annotate` method, and finally stores the result via
725    /// `set_inferred_type`.
726    pub fn annotate_in_place(&mut self, expr: &mut Expression) {
727        // 1. Recurse into children (bottom-up)
728        self.annotate_children_in_place(expr);
729
730        // 2. Compute this node's type using the read-only method
731        //    (children already have their types set, but `annotate` re-derives
732        //    from structure, which is fine since the structure hasn't changed)
733        let dt = self.annotate(expr);
734
735        // 3. Store on the node
736        if let Some(data_type) = dt {
737            expr.set_inferred_type(data_type);
738        }
739    }
740
741    /// Recursively annotate children of an expression in-place.
742    fn annotate_children_in_place(&mut self, expr: &mut Expression) {
743        match expr {
744            // Binary operations
745            Expression::And(op)
746            | Expression::Or(op)
747            | Expression::Add(op)
748            | Expression::Sub(op)
749            | Expression::Mul(op)
750            | Expression::Div(op)
751            | Expression::Mod(op)
752            | Expression::Eq(op)
753            | Expression::Neq(op)
754            | Expression::Lt(op)
755            | Expression::Lte(op)
756            | Expression::Gt(op)
757            | Expression::Gte(op)
758            | Expression::Concat(op)
759            | Expression::BitwiseAnd(op)
760            | Expression::BitwiseOr(op)
761            | Expression::BitwiseXor(op)
762            | Expression::Adjacent(op)
763            | Expression::TsMatch(op)
764            | Expression::PropertyEQ(op)
765            | Expression::ArrayContainsAll(op)
766            | Expression::ArrayContainedBy(op)
767            | Expression::ArrayOverlaps(op)
768            | Expression::JSONBContainsAllTopKeys(op)
769            | Expression::JSONBContainsAnyTopKeys(op)
770            | Expression::JSONBDeleteAtPath(op)
771            | Expression::ExtendsLeft(op)
772            | Expression::ExtendsRight(op)
773            | Expression::Is(op)
774            | Expression::MemberOf(op)
775            | Expression::Match(op)
776            | Expression::NullSafeEq(op)
777            | Expression::NullSafeNeq(op)
778            | Expression::Glob(op)
779            | Expression::BitwiseLeftShift(op)
780            | Expression::BitwiseRightShift(op) => {
781                self.annotate_in_place(&mut op.left);
782                self.annotate_in_place(&mut op.right);
783            }
784
785            // Like operations
786            Expression::Like(op) | Expression::ILike(op) => {
787                self.annotate_in_place(&mut op.left);
788                self.annotate_in_place(&mut op.right);
789            }
790
791            // Unary operations
792            Expression::Not(op) | Expression::Neg(op) | Expression::BitwiseNot(op) => {
793                self.annotate_in_place(&mut op.this);
794            }
795
796            // Cast
797            Expression::Cast(c) | Expression::TryCast(c) | Expression::SafeCast(c) => {
798                self.annotate_in_place(&mut c.this);
799            }
800
801            // Case
802            Expression::Case(c) => {
803                if let Some(ref mut operand) = c.operand {
804                    self.annotate_in_place(operand);
805                }
806                for (cond, then_expr) in &mut c.whens {
807                    self.annotate_in_place(cond);
808                    self.annotate_in_place(then_expr);
809                }
810                if let Some(ref mut else_expr) = c.else_ {
811                    self.annotate_in_place(else_expr);
812                }
813            }
814
815            // Alias
816            Expression::Alias(a) => {
817                self.annotate_in_place(&mut a.this);
818            }
819
820            // Column - leaf node, no children to recurse
821            Expression::Column(_) => {}
822
823            // Dot access - the field is an identifier, so only the base is typed
824            Expression::Dot(dot) => {
825                self.annotate_in_place(&mut dot.this);
826            }
827
828            // Function
829            Expression::Function(f) => {
830                for arg in &mut f.args {
831                    self.annotate_in_place(arg);
832                }
833            }
834            Expression::Unnest(unnest) => {
835                self.annotate_in_place(&mut unnest.this);
836                for expression in &mut unnest.expressions {
837                    self.annotate_in_place(expression);
838                }
839            }
840
841            // Dedicated conditional functions
842            Expression::IfFunc(f) => {
843                self.annotate_in_place(&mut f.condition);
844                self.annotate_in_place(&mut f.true_value);
845                if let Some(false_value) = &mut f.false_value {
846                    self.annotate_in_place(false_value);
847                }
848            }
849            Expression::Nvl2(f) => {
850                self.annotate_in_place(&mut f.this);
851                self.annotate_in_place(&mut f.true_value);
852                self.annotate_in_place(&mut f.false_value);
853            }
854
855            // AggregateFunction
856            Expression::AggregateFunction(f) => {
857                for arg in &mut f.args {
858                    self.annotate_in_place(arg);
859                }
860            }
861
862            // Dedicated aggregate / string functions
863            Expression::Count(f) => {
864                if let Some(this) = &mut f.this {
865                    self.annotate_in_place(this);
866                }
867                if let Some(filter) = &mut f.filter {
868                    self.annotate_in_place(filter);
869                }
870            }
871            Expression::GroupConcat(f) => {
872                self.annotate_in_place(&mut f.this);
873                if let Some(separator) = &mut f.separator {
874                    self.annotate_in_place(separator);
875                }
876                if let Some(order_by) = &mut f.order_by {
877                    for ordered in order_by {
878                        self.annotate_in_place(&mut ordered.this);
879                    }
880                }
881                if let Some(filter) = &mut f.filter {
882                    self.annotate_in_place(filter);
883                }
884            }
885            Expression::StringAgg(f) => {
886                self.annotate_in_place(&mut f.this);
887                if let Some(separator) = &mut f.separator {
888                    self.annotate_in_place(separator);
889                }
890                if let Some(order_by) = &mut f.order_by {
891                    for ordered in order_by {
892                        self.annotate_in_place(&mut ordered.this);
893                    }
894                }
895                if let Some(filter) = &mut f.filter {
896                    self.annotate_in_place(filter);
897                }
898                if let Some(limit) = &mut f.limit {
899                    self.annotate_in_place(limit);
900                }
901            }
902            Expression::ListAgg(f) => {
903                self.annotate_in_place(&mut f.this);
904                if let Some(separator) = &mut f.separator {
905                    self.annotate_in_place(separator);
906                }
907                if let Some(order_by) = &mut f.order_by {
908                    for ordered in order_by {
909                        self.annotate_in_place(&mut ordered.this);
910                    }
911                }
912                if let Some(filter) = &mut f.filter {
913                    self.annotate_in_place(filter);
914                }
915                if let Some(ListAggOverflow::Truncate {
916                    filler: Some(filler),
917                    ..
918                }) = &mut f.on_overflow
919                {
920                    self.annotate_in_place(filler);
921                }
922            }
923            Expression::SumIf(f) => {
924                self.annotate_in_place(&mut f.this);
925                self.annotate_in_place(&mut f.condition);
926                if let Some(filter) = &mut f.filter {
927                    self.annotate_in_place(filter);
928                }
929            }
930
931            // WindowFunction
932            Expression::WindowFunction(w) => {
933                self.annotate_in_place(&mut w.this);
934            }
935
936            // Subquery
937            Expression::Subquery(s) => {
938                self.annotate_in_place(&mut s.this);
939            }
940
941            // UnaryFunc variants
942            Expression::Upper(f)
943            | Expression::Lower(f)
944            | Expression::Length(f)
945            | Expression::LTrim(f)
946            | Expression::RTrim(f)
947            | Expression::Reverse(f)
948            | Expression::Abs(f)
949            | Expression::Sqrt(f)
950            | Expression::Cbrt(f)
951            | Expression::Ln(f)
952            | Expression::Exp(f)
953            | Expression::Sign(f)
954            | Expression::Date(f)
955            | Expression::Time(f)
956            | Expression::Explode(f)
957            | Expression::ExplodeOuter(f)
958            | Expression::MapFromEntries(f)
959            | Expression::MapKeys(f)
960            | Expression::MapValues(f)
961            | Expression::ArrayLength(f)
962            | Expression::ArraySize(f)
963            | Expression::Cardinality(f)
964            | Expression::ArrayReverse(f)
965            | Expression::ArrayDistinct(f)
966            | Expression::ArrayFlatten(f)
967            | Expression::ArrayCompact(f)
968            | Expression::ToArray(f)
969            | Expression::JsonArrayLength(f)
970            | Expression::JsonKeys(f)
971            | Expression::JsonType(f)
972            | Expression::ParseJson(f)
973            | Expression::ToJson(f)
974            | Expression::Year(f)
975            | Expression::Month(f)
976            | Expression::Day(f)
977            | Expression::Hour(f)
978            | Expression::Minute(f)
979            | Expression::Second(f)
980            | Expression::Initcap(f)
981            | Expression::Ascii(f)
982            | Expression::Chr(f)
983            | Expression::Soundex(f)
984            | Expression::ByteLength(f)
985            | Expression::Hex(f)
986            | Expression::LowerHex(f)
987            | Expression::Unicode(f)
988            | Expression::Typeof(f)
989            | Expression::BitwiseCount(f)
990            | Expression::Epoch(f)
991            | Expression::EpochMs(f)
992            | Expression::Radians(f)
993            | Expression::Degrees(f)
994            | Expression::Sin(f)
995            | Expression::Cos(f)
996            | Expression::Tan(f)
997            | Expression::Asin(f)
998            | Expression::Acos(f)
999            | Expression::Atan(f)
1000            | Expression::IsNan(f)
1001            | Expression::IsInf(f) => {
1002                self.annotate_in_place(&mut f.this);
1003            }
1004
1005            // BinaryFunc variants
1006            Expression::Power(f)
1007            | Expression::NullIf(f)
1008            | Expression::IfNull(f)
1009            | Expression::Nvl(f)
1010            | Expression::Contains(f)
1011            | Expression::StartsWith(f)
1012            | Expression::EndsWith(f)
1013            | Expression::Levenshtein(f)
1014            | Expression::ModFunc(f)
1015            | Expression::IntDiv(f)
1016            | Expression::Atan2(f)
1017            | Expression::AddMonths(f)
1018            | Expression::MonthsBetween(f)
1019            | Expression::NextDay(f)
1020            | Expression::UnixToTimeStr(f)
1021            | Expression::ArrayContains(f)
1022            | Expression::ArrayPosition(f)
1023            | Expression::ArrayAppend(f)
1024            | Expression::ArrayPrepend(f)
1025            | Expression::ArrayUnion(f)
1026            | Expression::ArrayExcept(f)
1027            | Expression::ArrayRemove(f)
1028            | Expression::StarMap(f)
1029            | Expression::MapFromArrays(f)
1030            | Expression::MapContainsKey(f)
1031            | Expression::ElementAt(f)
1032            | Expression::JsonMergePatch(f) => {
1033                self.annotate_in_place(&mut f.this);
1034                self.annotate_in_place(&mut f.expression);
1035            }
1036
1037            // VarArgFunc variants
1038            Expression::Coalesce(f)
1039            | Expression::Greatest(f)
1040            | Expression::Least(f)
1041            | Expression::ArrayConcat(f)
1042            | Expression::ArrayIntersect(f)
1043            | Expression::ArrayZip(f)
1044            | Expression::MapConcat(f)
1045            | Expression::JsonArray(f) => {
1046                for e in &mut f.expressions {
1047                    self.annotate_in_place(e);
1048                }
1049            }
1050
1051            // AggFunc variants
1052            Expression::Sum(f)
1053            | Expression::Avg(f)
1054            | Expression::Min(f)
1055            | Expression::Max(f)
1056            | Expression::ArrayAgg(f)
1057            | Expression::CountIf(f)
1058            | Expression::Stddev(f)
1059            | Expression::StddevPop(f)
1060            | Expression::StddevSamp(f)
1061            | Expression::Variance(f)
1062            | Expression::VarPop(f)
1063            | Expression::VarSamp(f)
1064            | Expression::Median(f)
1065            | Expression::Mode(f)
1066            | Expression::First(f)
1067            | Expression::Last(f)
1068            | Expression::AnyValue(f)
1069            | Expression::ApproxDistinct(f)
1070            | Expression::ApproxCountDistinct(f)
1071            | Expression::LogicalAnd(f)
1072            | Expression::LogicalOr(f)
1073            | Expression::Skewness(f)
1074            | Expression::ArrayConcatAgg(f)
1075            | Expression::ArrayUniqueAgg(f)
1076            | Expression::BoolXorAgg(f)
1077            | Expression::BitwiseAndAgg(f)
1078            | Expression::BitwiseOrAgg(f)
1079            | Expression::BitwiseXorAgg(f) => {
1080                self.annotate_in_place(&mut f.this);
1081            }
1082
1083            // Select - recurse into expressions
1084            Expression::Select(s) => {
1085                for e in &mut s.expressions {
1086                    self.annotate_in_place(e);
1087                }
1088            }
1089
1090            // Everything else - no children to recurse or not value-producing
1091            _ => {}
1092        }
1093    }
1094
1095    /// Annotate math functions like FLOOR/CEIL that return Double for integer inputs
1096    /// and preserve the input type otherwise (matching sqlglot's _annotate_math_functions).
1097    fn annotate_math_function(&mut self, arg: &Expression) -> Option<DataType> {
1098        let input_type = self.annotate(arg)?;
1099        match input_type {
1100            DataType::TinyInt { .. }
1101            | DataType::SmallInt { .. }
1102            | DataType::Int { .. }
1103            | DataType::BigInt { .. } => Some(DataType::Double {
1104                precision: None,
1105                scale: None,
1106            }),
1107            other => Some(other),
1108        }
1109    }
1110
1111    /// Annotate a subscript/bracket expression (array[index] or map[key])
1112    fn annotate_subscript(&mut self, sub: &Subscript) -> Option<DataType> {
1113        let base_type = self.annotate(&sub.this)?;
1114
1115        match base_type {
1116            DataType::Array { element_type, .. } => Some(*element_type),
1117            DataType::Map { value_type, .. } => Some(*value_type),
1118            DataType::Json | DataType::JsonB => Some(DataType::Json), // JSON indexing returns JSON
1119            DataType::VarChar { .. } | DataType::Text => {
1120                // String indexing returns a character
1121                Some(DataType::VarChar {
1122                    length: Some(1),
1123                    parenthesized_length: false,
1124                })
1125            }
1126            _ => None,
1127        }
1128    }
1129
1130    /// Annotate a named field lookup from the type of its base expression.
1131    fn annotate_dot(&mut self, dot: &DotAccess) -> Option<DataType> {
1132        let base_type = self.annotate(&dot.this)?;
1133        let DataType::Struct { fields, .. } = base_type else {
1134            return None;
1135        };
1136        let field_name = normalize_name(&dot.field.name, self._dialect, false, true);
1137
1138        fields
1139            .into_iter()
1140            .find(|field| normalize_name(&field.name, self._dialect, false, true) == field_name)
1141            .map(|field| field.data_type)
1142    }
1143
1144    /// Annotate a STRUCT literal
1145    fn annotate_struct(&mut self, s: &Struct) -> Option<DataType> {
1146        let fields: Vec<StructField> = s
1147            .fields
1148            .iter()
1149            .map(|(name, expr)| {
1150                let field_type = self.annotate(expr).unwrap_or(DataType::Unknown);
1151                StructField::new(name.clone().unwrap_or_default(), field_type)
1152            })
1153            .collect();
1154        Some(DataType::Struct {
1155            fields,
1156            nested: false,
1157        })
1158    }
1159
1160    /// Annotate a MAP literal
1161    fn annotate_map(&mut self, map: &Map) -> Option<DataType> {
1162        let key_type = if let Some(first_key) = map.keys.first() {
1163            self.annotate(first_key).unwrap_or(DataType::Unknown)
1164        } else {
1165            DataType::Unknown
1166        };
1167
1168        let value_type = if let Some(first_value) = map.values.first() {
1169            self.annotate(first_value).unwrap_or(DataType::Unknown)
1170        } else {
1171            DataType::Unknown
1172        };
1173
1174        Some(DataType::Map {
1175            key_type: Box::new(key_type),
1176            value_type: Box::new(value_type),
1177        })
1178    }
1179
1180    /// Annotate a SetOperation (UNION/INTERSECT/EXCEPT)
1181    /// Returns None since set operations produce relation types, not scalar types
1182    fn annotate_set_operation(
1183        &mut self,
1184        _left: &Expression,
1185        _right: &Expression,
1186    ) -> Option<DataType> {
1187        // Set operations produce relations, not scalar types
1188        // The column types would be coerced between left and right
1189        // For now, return None as this is a relation-level type
1190        None
1191    }
1192
1193    /// Annotate a LATERAL VIEW expression
1194    fn annotate_lateral_view(&mut self, lv: &crate::expressions::LateralView) -> Option<DataType> {
1195        // The type depends on the table-generating function
1196        self.annotate(&lv.this)
1197    }
1198
1199    /// Annotate a literal value
1200    fn annotate_literal(&self, lit: &Literal) -> Option<DataType> {
1201        match lit {
1202            Literal::String(_)
1203            | Literal::NationalString(_)
1204            | Literal::TripleQuotedString(_, _)
1205            | Literal::EscapeString(_)
1206            | Literal::DollarString(_)
1207            | Literal::RawString(_) => Some(DataType::VarChar {
1208                length: None,
1209                parenthesized_length: false,
1210            }),
1211            Literal::Number(n) => {
1212                // Try to determine if it's an integer or float
1213                if n.contains('.') || n.contains('e') || n.contains('E') {
1214                    Some(DataType::Double {
1215                        precision: None,
1216                        scale: None,
1217                    })
1218                } else {
1219                    // Check if it fits in an Int or needs BigInt
1220                    if let Ok(_) = n.parse::<i32>() {
1221                        Some(DataType::Int {
1222                            length: None,
1223                            integer_spelling: false,
1224                        })
1225                    } else {
1226                        Some(DataType::BigInt { length: None })
1227                    }
1228                }
1229            }
1230            Literal::HexString(_) | Literal::BitString(_) | Literal::ByteString(_) => {
1231                Some(DataType::VarBinary { length: None })
1232            }
1233            Literal::HexNumber(_) => Some(DataType::BigInt { length: None }),
1234            Literal::Date(_) => Some(DataType::Date),
1235            Literal::Time(_) => Some(DataType::Time {
1236                precision: None,
1237                timezone: false,
1238            }),
1239            Literal::Timestamp(_) => Some(DataType::Timestamp {
1240                precision: None,
1241                timezone: false,
1242            }),
1243            Literal::Datetime(_) => Some(DataType::Custom {
1244                name: "DATETIME".to_string(),
1245            }),
1246        }
1247    }
1248
1249    /// Annotate an arithmetic binary operation
1250    fn annotate_arithmetic(&mut self, op: &BinaryOp) -> Option<DataType> {
1251        let left_type = self.annotate(&op.left);
1252        let right_type = self.annotate(&op.right);
1253
1254        match (left_type, right_type) {
1255            (Some(l), Some(r)) => self.coerce_types(&l, &r),
1256            (Some(t), None) | (None, Some(t)) => Some(t),
1257            (None, None) => None,
1258        }
1259    }
1260
1261    /// Annotate a function call
1262    fn annotate_function(&mut self, func: &Function) -> Option<DataType> {
1263        let func_name = func.name.to_uppercase();
1264
1265        if self._dialect == Some(DialectType::DuckDB) && !func.quoted && func_name == "DATE_TRUNC" {
1266            return self.annotate_duckdb_date_trunc(func);
1267        }
1268
1269        // Check known function return types
1270        if let Some(return_type) = self.function_return_types.get(&func_name) {
1271            if *return_type != DataType::Unknown {
1272                return Some(return_type.clone());
1273            }
1274        }
1275
1276        // For functions with Unknown return type, infer from arguments
1277        match func_name.as_str() {
1278            "UNNEST" => func.args.first().and_then(|arg| match self.annotate(arg) {
1279                Some(DataType::Array { element_type, .. }) => Some(*element_type),
1280                _ => None,
1281            }),
1282            "COALESCE" | "IFNULL" | "NVL" | "ISNULL" => {
1283                // Return type of first non-null argument
1284                for arg in &func.args {
1285                    if let Some(arg_type) = self.annotate(arg) {
1286                        return Some(arg_type);
1287                    }
1288                }
1289                None
1290            }
1291            "NULLIF" => {
1292                // Return type of first argument
1293                func.args.first().and_then(|arg| self.annotate(arg))
1294            }
1295            "GREATEST" | "LEAST" => {
1296                // Coerce all argument types
1297                self.coerce_arg_types(&func.args)
1298            }
1299            "IF" | "IIF" => {
1300                // Return type of THEN/ELSE branches
1301                if func.args.len() >= 2 {
1302                    self.annotate(&func.args[1])
1303                } else {
1304                    None
1305                }
1306            }
1307            _ => {
1308                // Unknown function - try to infer from first argument
1309                func.args.first().and_then(|arg| self.annotate(arg))
1310            }
1311        }
1312    }
1313
1314    /// Infer DuckDB's overloaded DATE_TRUNC return type from its temporal value argument.
1315    fn annotate_duckdb_date_trunc(&mut self, func: &Function) -> Option<DataType> {
1316        if func.args.len() != 2 {
1317            return None;
1318        }
1319
1320        match self.annotate(&func.args[1])? {
1321            DataType::Date => Some(DataType::Timestamp {
1322                precision: None,
1323                timezone: false,
1324            }),
1325            DataType::Timestamp { timezone, .. } => Some(DataType::Timestamp {
1326                precision: None,
1327                timezone,
1328            }),
1329            DataType::Interval { .. } => Some(DataType::Interval {
1330                unit: None,
1331                to: None,
1332            }),
1333            _ => None,
1334        }
1335    }
1336
1337    /// Annotate IF/IIF/IFF conditional function
1338    fn annotate_if_func(&mut self, func: &IfFunc) -> Option<DataType> {
1339        let true_type = self.annotate(&func.true_value);
1340        let false_type = func
1341            .false_value
1342            .as_ref()
1343            .and_then(|expr| self.annotate(expr));
1344
1345        match (true_type, false_type) {
1346            (Some(left), Some(right)) => self.coerce_types(&left, &right),
1347            (Some(dt), None) | (None, Some(dt)) => Some(dt),
1348            (None, None) => None,
1349        }
1350    }
1351
1352    /// Annotate NVL2 conditional function from its true/false branches
1353    fn annotate_nvl2(&mut self, func: &Nvl2Func) -> Option<DataType> {
1354        let true_type = self.annotate(&func.true_value);
1355        let false_type = self.annotate(&func.false_value);
1356
1357        match (true_type, false_type) {
1358            (Some(left), Some(right)) => self.coerce_types(&left, &right),
1359            (Some(dt), None) | (None, Some(dt)) => Some(dt),
1360            (None, None) => None,
1361        }
1362    }
1363
1364    /// Get return type for aggregate functions
1365    fn get_aggregate_return_type(
1366        &mut self,
1367        func_name: &str,
1368        args: &[Expression],
1369    ) -> Option<DataType> {
1370        match func_name {
1371            "COUNT" | "COUNT_IF" => Some(DataType::BigInt { length: None }),
1372            "SUM_IF" => {
1373                if let Some(arg) = args.first() {
1374                    self.annotate_sum(arg)
1375                } else {
1376                    Some(DataType::Decimal {
1377                        precision: None,
1378                        scale: None,
1379                    })
1380                }
1381            }
1382            "SUM" => {
1383                if let Some(arg) = args.first() {
1384                    self.annotate_sum(arg)
1385                } else {
1386                    Some(DataType::Decimal {
1387                        precision: None,
1388                        scale: None,
1389                    })
1390                }
1391            }
1392            "AVG" => Some(DataType::Double {
1393                precision: None,
1394                scale: None,
1395            }),
1396            "MIN" | "MAX" => {
1397                // DuckDB's two-argument MIN/MAX aggregate overloads return the
1398                // bottom/top N values as a list. Other parsed aggregate forms
1399                // preserve the input type.
1400                let input_type = args.first().and_then(|arg| self.annotate(arg));
1401                if args.len() == 2 {
1402                    input_type.map(|element_type| DataType::Array {
1403                        element_type: Box::new(element_type),
1404                        dimension: None,
1405                    })
1406                } else {
1407                    input_type
1408                }
1409            }
1410            "STRING_AGG" | "GROUP_CONCAT" | "LISTAGG" | "ARRAY_AGG" => Some(DataType::VarChar {
1411                length: None,
1412                parenthesized_length: false,
1413            }),
1414            "BOOL_AND" | "BOOL_OR" | "EVERY" | "ANY" | "SOME" => Some(DataType::Boolean),
1415            "BIT_AND" | "BIT_OR" | "BIT_XOR" => Some(DataType::BigInt { length: None }),
1416            "STDDEV" | "STDDEV_POP" | "STDDEV_SAMP" | "VARIANCE" | "VAR_POP" | "VAR_SAMP" => {
1417                Some(DataType::Double {
1418                    precision: None,
1419                    scale: None,
1420                })
1421            }
1422            "PERCENTILE_CONT" | "PERCENTILE_DISC" | "MEDIAN" => {
1423                args.first().and_then(|arg| self.annotate(arg))
1424            }
1425            _ => None,
1426        }
1427    }
1428
1429    /// Annotate SUM function - promotes to at least BigInt
1430    fn annotate_sum(&mut self, arg: &Expression) -> Option<DataType> {
1431        match self.annotate(arg) {
1432            Some(DataType::TinyInt { .. })
1433            | Some(DataType::SmallInt { .. })
1434            | Some(DataType::Int { .. }) => Some(DataType::BigInt { length: None }),
1435            Some(DataType::BigInt { .. }) => Some(DataType::BigInt { length: None }),
1436            Some(DataType::Float { .. }) | Some(DataType::Double { .. }) => {
1437                Some(DataType::Double {
1438                    precision: None,
1439                    scale: None,
1440                })
1441            }
1442            Some(DataType::Decimal { precision, scale }) => {
1443                Some(DataType::Decimal { precision, scale })
1444            }
1445            _ => Some(DataType::Decimal {
1446                precision: None,
1447                scale: None,
1448            }),
1449        }
1450    }
1451
1452    /// Coerce multiple argument types to a common type
1453    fn coerce_arg_types(&mut self, args: &[Expression]) -> Option<DataType> {
1454        let mut result_type: Option<DataType> = None;
1455        for arg in args {
1456            if let Some(arg_type) = self.annotate(arg) {
1457                result_type = match result_type {
1458                    Some(t) => self.coerce_types(&t, &arg_type),
1459                    None => Some(arg_type),
1460                };
1461            }
1462        }
1463        result_type
1464    }
1465
1466    /// Coerce two types to a common type
1467    fn coerce_types(&self, left: &DataType, right: &DataType) -> Option<DataType> {
1468        // If types are the same, return that type
1469        if left == right {
1470            return Some(left.clone());
1471        }
1472
1473        // Special case: Interval + Date/Timestamp
1474        match (left, right) {
1475            (DataType::Date, DataType::Interval { .. })
1476            | (DataType::Interval { .. }, DataType::Date) => return Some(DataType::Date),
1477            (
1478                DataType::Timestamp {
1479                    precision,
1480                    timezone,
1481                },
1482                DataType::Interval { .. },
1483            )
1484            | (
1485                DataType::Interval { .. },
1486                DataType::Timestamp {
1487                    precision,
1488                    timezone,
1489                },
1490            ) => {
1491                return Some(DataType::Timestamp {
1492                    precision: *precision,
1493                    timezone: *timezone,
1494                });
1495            }
1496            _ => {}
1497        }
1498
1499        // Coerce based on class
1500        let left_class = TypeCoercionClass::from_data_type(left);
1501        let right_class = TypeCoercionClass::from_data_type(right);
1502
1503        match (left_class, right_class) {
1504            // Same class: use higher-precision type within class
1505            (Some(lc), Some(rc)) if lc == rc => {
1506                // For numeric, choose wider type
1507                if lc == TypeCoercionClass::Numeric {
1508                    Some(self.wider_numeric_type(left, right))
1509                } else {
1510                    // For text and timelike, left wins by default
1511                    Some(left.clone())
1512                }
1513            }
1514            // Different classes: higher-priority class wins
1515            (Some(lc), Some(rc)) => {
1516                if lc > rc {
1517                    Some(left.clone())
1518                } else {
1519                    Some(right.clone())
1520                }
1521            }
1522            // One unknown: use the known type
1523            (Some(_), None) => Some(left.clone()),
1524            (None, Some(_)) => Some(right.clone()),
1525            // Both unknown: return unknown
1526            (None, None) => Some(DataType::Unknown),
1527        }
1528    }
1529
1530    /// Get the wider numeric type
1531    fn wider_numeric_type(&self, left: &DataType, right: &DataType) -> DataType {
1532        let order = |dt: &DataType| -> u8 {
1533            match dt {
1534                DataType::Boolean => 0,
1535                DataType::TinyInt { .. } => 1,
1536                DataType::SmallInt { .. } => 2,
1537                DataType::Int { .. } => 3,
1538                DataType::BigInt { .. } => 4,
1539                DataType::Float { .. } => 5,
1540                DataType::Double { .. } => 6,
1541                DataType::Decimal { .. } => 7,
1542                _ => 0,
1543            }
1544        };
1545
1546        if order(left) >= order(right) {
1547            left.clone()
1548        } else {
1549            right.clone()
1550        }
1551    }
1552}
1553
1554/// A schema layer whose entries are visible only while annotating one query
1555/// scope. The parent contains physical tables and any correlated outer scope;
1556/// CTE, derived-table, table-alias, and table-valued-function outputs stay in
1557/// this layer and therefore cannot leak into sibling scopes.
1558struct ScopedSchema<'a> {
1559    parent: Option<&'a dyn Schema>,
1560    tables: HashMap<String, HashMap<String, DataType>>,
1561    dialect: Option<DialectType>,
1562}
1563
1564impl<'a> ScopedSchema<'a> {
1565    fn new(parent: Option<&'a dyn Schema>, dialect: Option<DialectType>) -> Self {
1566        Self {
1567            parent,
1568            tables: HashMap::new(),
1569            dialect,
1570        }
1571    }
1572
1573    fn normalized(&self, name: &str, is_table: bool) -> String {
1574        normalize_name(name, self.dialect, is_table, true)
1575    }
1576
1577    fn local_column_type(&self, table: &str, column: &str) -> Option<DataType> {
1578        let table = self.normalized(table, true);
1579        let column = self.normalized(column, false);
1580        self.tables
1581            .get(&table)
1582            .and_then(|columns| columns.get(&column))
1583            .cloned()
1584    }
1585
1586    fn local_tables_for_column(&self, column: &str) -> Vec<String> {
1587        let column = self.normalized(column, false);
1588        self.tables
1589            .iter()
1590            .filter_map(|(table, columns)| columns.contains_key(&column).then(|| table.clone()))
1591            .collect()
1592    }
1593}
1594
1595impl Schema for ScopedSchema<'_> {
1596    fn dialect(&self) -> Option<DialectType> {
1597        self.dialect
1598            .or_else(|| self.parent.and_then(Schema::dialect))
1599    }
1600
1601    fn add_table(
1602        &mut self,
1603        table: &str,
1604        columns: &[(String, DataType)],
1605        _dialect: Option<DialectType>,
1606    ) -> SchemaResult<()> {
1607        let table = self.normalized(table, true);
1608        let columns = columns
1609            .iter()
1610            .map(|(name, data_type)| (self.normalized(name, false), data_type.clone()))
1611            .collect();
1612        self.tables.insert(table, columns);
1613        Ok(())
1614    }
1615
1616    fn column_names(&self, table: &str) -> SchemaResult<Vec<String>> {
1617        let table = self.normalized(table, true);
1618        if let Some(columns) = self.tables.get(&table) {
1619            return Ok(columns.keys().cloned().collect());
1620        }
1621        self.parent
1622            .ok_or_else(|| SchemaError::TableNotFound(table.clone()))?
1623            .column_names(&table)
1624    }
1625
1626    fn get_column_type(&self, table: &str, column: &str) -> SchemaResult<DataType> {
1627        if table.is_empty() {
1628            let local_tables = self.local_tables_for_column(column);
1629            return match local_tables.as_slice() {
1630                [local_table] => self.get_column_type(local_table, column),
1631                [] => self
1632                    .parent
1633                    .ok_or_else(|| SchemaError::ColumnNotFound {
1634                        table: String::new(),
1635                        column: column.to_string(),
1636                    })?
1637                    .get_column_type(table, column),
1638                _ => Err(SchemaError::AmbiguousTable {
1639                    table: String::new(),
1640                    matches: local_tables.join(", "),
1641                }),
1642            };
1643        }
1644
1645        let normalized_table = self.normalized(table, true);
1646        if self.tables.contains_key(&normalized_table) {
1647            return self.local_column_type(table, column).ok_or_else(|| {
1648                SchemaError::ColumnNotFound {
1649                    table: table.to_string(),
1650                    column: column.to_string(),
1651                }
1652            });
1653        }
1654
1655        self.parent
1656            .ok_or_else(|| SchemaError::ColumnNotFound {
1657                table: table.to_string(),
1658                column: column.to_string(),
1659            })?
1660            .get_column_type(table, column)
1661    }
1662
1663    fn has_column(&self, table: &str, column: &str) -> bool {
1664        self.get_column_type(table, column).is_ok()
1665    }
1666
1667    fn supported_table_args(&self) -> &[&str] {
1668        TABLE_PARTS
1669    }
1670
1671    fn is_empty(&self) -> bool {
1672        self.tables.is_empty() && self.parent.is_none_or(Schema::is_empty)
1673    }
1674
1675    fn depth(&self) -> usize {
1676        self.parent.map_or(1, |schema| schema.depth().max(1))
1677    }
1678
1679    fn find_tables_for_column(&self, column: &str) -> Vec<String> {
1680        let mut tables = self.local_tables_for_column(column);
1681        if let Some(parent) = self.parent {
1682            tables.extend(parent.find_tables_for_column(column));
1683        }
1684        let mut seen = HashSet::new();
1685        tables.retain(|table| seen.insert(table.clone()));
1686        tables
1687    }
1688}
1689
1690type OutputColumns = Vec<(String, DataType)>;
1691
1692fn table_name(table: &crate::expressions::TableRef) -> String {
1693    let mut parts = Vec::new();
1694    if let Some(catalog) = &table.catalog {
1695        parts.push(catalog.name.as_str());
1696    }
1697    if let Some(schema) = &table.schema {
1698        parts.push(schema.name.as_str());
1699    }
1700    parts.push(table.name.name.as_str());
1701    parts.join(".")
1702}
1703
1704fn table_columns(schema: &dyn Schema, table: &str) -> OutputColumns {
1705    schema
1706        .column_names(table)
1707        .unwrap_or_default()
1708        .into_iter()
1709        .map(|column| {
1710            let data_type = schema
1711                .get_column_type(table, &column)
1712                .unwrap_or(DataType::Unknown);
1713            (column, data_type)
1714        })
1715        .collect()
1716}
1717
1718fn apply_column_aliases(
1719    mut columns: OutputColumns,
1720    aliases: &[crate::expressions::Identifier],
1721) -> OutputColumns {
1722    for ((name, _), alias) in columns.iter_mut().zip(aliases) {
1723        *name = alias.name.clone();
1724    }
1725    columns
1726}
1727
1728fn projection_name(expression: &Expression) -> Option<String> {
1729    match expression {
1730        Expression::Alias(alias) => Some(alias.alias.name.clone()),
1731        Expression::Column(column) => Some(column.name.name.clone()),
1732        Expression::Identifier(identifier) => Some(identifier.name.clone()),
1733        _ => None,
1734    }
1735}
1736
1737fn projection_type(expression: &Expression) -> DataType {
1738    expression
1739        .inferred_type()
1740        .or_else(|| match expression {
1741            Expression::Alias(alias) => alias.this.inferred_type(),
1742            _ => None,
1743        })
1744        .cloned()
1745        .unwrap_or(DataType::Unknown)
1746}
1747
1748fn query_outputs(expressions: &[Expression]) -> OutputColumns {
1749    expressions
1750        .iter()
1751        .filter_map(|expression| {
1752            projection_name(expression).map(|name| (name, projection_type(expression)))
1753        })
1754        .collect()
1755}
1756
1757fn array_element_type(data_type: Option<&DataType>) -> DataType {
1758    match data_type {
1759        Some(DataType::Array { element_type, .. }) => (**element_type).clone(),
1760        _ => DataType::Unknown,
1761    }
1762}
1763
1764fn unnest_output_types(unnest: &crate::expressions::UnnestFunc) -> Vec<DataType> {
1765    let mut types = vec![array_element_type(unnest.this.inferred_type())];
1766    types.extend(
1767        unnest
1768            .expressions
1769            .iter()
1770            .map(|expression| array_element_type(expression.inferred_type())),
1771    );
1772    if unnest.with_ordinality || unnest.offset_alias.is_some() {
1773        types.push(DataType::BigInt { length: None });
1774    }
1775    types
1776}
1777
1778fn virtual_output_columns(
1779    expression: &Expression,
1780    source_alias: &str,
1781    column_aliases: &[crate::expressions::Identifier],
1782) -> OutputColumns {
1783    let (types, offset_alias) = match expression {
1784        Expression::Unnest(unnest) => (unnest_output_types(unnest), unnest.offset_alias.as_ref()),
1785        Expression::Explode(explode) | Expression::ExplodeOuter(explode) => {
1786            (vec![array_element_type(explode.this.inferred_type())], None)
1787        }
1788        Expression::Function(function) if function.name.eq_ignore_ascii_case("UNNEST") => (
1789            function
1790                .args
1791                .iter()
1792                .map(|argument| array_element_type(argument.inferred_type()))
1793                .collect(),
1794            None,
1795        ),
1796        _ => return Vec::new(),
1797    };
1798
1799    if column_aliases.is_empty() {
1800        let mut columns = Vec::new();
1801        if let Some(data_type) = types.first() {
1802            columns.push((source_alias.to_string(), data_type.clone()));
1803        }
1804        if let Some(offset_alias) = offset_alias {
1805            columns.push((offset_alias.name.clone(), DataType::BigInt { length: None }));
1806        }
1807        columns
1808    } else {
1809        column_aliases
1810            .iter()
1811            .zip(types)
1812            .map(|(alias, data_type)| (alias.name.clone(), data_type))
1813            .collect()
1814    }
1815}
1816
1817fn annotate_relation_source(
1818    expression: &mut Expression,
1819    schema: &mut ScopedSchema<'_>,
1820    dialect: Option<DialectType>,
1821) {
1822    match expression {
1823        Expression::Table(table) => {
1824            let source_table = table_name(table);
1825            let mut columns = table_columns(schema, &source_table);
1826            columns = apply_column_aliases(columns, &table.column_aliases);
1827            let visible_name = table
1828                .alias
1829                .as_ref()
1830                .map(|alias| alias.name.as_str())
1831                .unwrap_or(table.name.name.as_str());
1832            let _ = schema.add_table(visible_name, &columns, dialect);
1833        }
1834        Expression::Subquery(subquery) => {
1835            let mut columns = annotate_scoped_expression(&mut subquery.this, Some(schema), dialect);
1836            columns = apply_column_aliases(columns, &subquery.column_aliases);
1837            if let Some((_, first_type)) = columns.first() {
1838                subquery.inferred_type = Some(first_type.clone());
1839            }
1840            if let Some(alias) = &subquery.alias {
1841                let _ = schema.add_table(&alias.name, &columns, dialect);
1842            }
1843        }
1844        Expression::Alias(alias) => {
1845            match &mut alias.this {
1846                Expression::Subquery(subquery) => {
1847                    let columns =
1848                        annotate_scoped_expression(&mut subquery.this, Some(schema), dialect);
1849                    let columns = apply_column_aliases(columns, &alias.column_aliases);
1850                    let _ = schema.add_table(&alias.alias.name, &columns, dialect);
1851                    return;
1852                }
1853                _ => {
1854                    let mut annotator = TypeAnnotator::new(Some(schema), dialect);
1855                    annotator.annotate_in_place(&mut alias.this);
1856                }
1857            }
1858            let columns =
1859                virtual_output_columns(&alias.this, &alias.alias.name, &alias.column_aliases);
1860            if !columns.is_empty() {
1861                let _ = schema.add_table(&alias.alias.name, &columns, dialect);
1862            }
1863        }
1864        Expression::Unnest(_) => {
1865            let mut annotator = TypeAnnotator::new(Some(schema), dialect);
1866            annotator.annotate_in_place(expression);
1867            if let Expression::Unnest(unnest) = expression {
1868                if let Some(alias) = &unnest.alias {
1869                    let alias_name = alias.name.clone();
1870                    let columns = unnest_output_types(unnest)
1871                        .into_iter()
1872                        .next()
1873                        .map(|data_type| vec![(alias_name.clone(), data_type)])
1874                        .unwrap_or_default();
1875                    let _ = schema.add_table(&alias_name, &columns, dialect);
1876                }
1877            }
1878        }
1879        Expression::Lateral(lateral) => {
1880            let mut annotator = TypeAnnotator::new(Some(schema), dialect);
1881            annotator.annotate_in_place(&mut lateral.this);
1882            if let Some(alias) = &lateral.alias {
1883                let aliases: Vec<_> = lateral
1884                    .column_aliases
1885                    .iter()
1886                    .map(crate::expressions::Identifier::new)
1887                    .collect();
1888                let columns = virtual_output_columns(&lateral.this, alias, &aliases);
1889                if !columns.is_empty() {
1890                    let _ = schema.add_table(alias, &columns, dialect);
1891                }
1892            }
1893        }
1894        Expression::Paren(paren) => annotate_relation_source(&mut paren.this, schema, dialect),
1895        _ => {
1896            let mut annotator = TypeAnnotator::new(Some(schema), dialect);
1897            annotator.annotate_in_place(expression);
1898        }
1899    }
1900}
1901
1902fn annotate_with(
1903    with: &mut Option<crate::expressions::With>,
1904    schema: &mut ScopedSchema<'_>,
1905    dialect: Option<DialectType>,
1906) {
1907    if let Some(with) = with {
1908        for cte in &mut with.ctes {
1909            let columns = annotate_scoped_expression(&mut cte.this, Some(schema), dialect);
1910            let columns = apply_column_aliases(columns, &cte.columns);
1911            let _ = schema.add_table(&cte.alias.name, &columns, dialect);
1912        }
1913    }
1914}
1915
1916fn annotate_select(
1917    select: &mut crate::expressions::Select,
1918    parent: Option<&dyn Schema>,
1919    dialect: Option<DialectType>,
1920) -> OutputColumns {
1921    let mut schema = ScopedSchema::new(parent, dialect);
1922    annotate_with(&mut select.with, &mut schema, dialect);
1923
1924    if let Some(from) = &mut select.from {
1925        for source in &mut from.expressions {
1926            annotate_relation_source(source, &mut schema, dialect);
1927        }
1928    }
1929    for join in &mut select.joins {
1930        annotate_relation_source(&mut join.this, &mut schema, dialect);
1931    }
1932
1933    let mut annotator = TypeAnnotator::new(Some(&schema), dialect);
1934    for expression in &mut select.expressions {
1935        annotator.annotate_in_place(expression);
1936    }
1937    query_outputs(&select.expressions)
1938}
1939
1940fn annotate_scoped_expression(
1941    expression: &mut Expression,
1942    parent: Option<&dyn Schema>,
1943    dialect: Option<DialectType>,
1944) -> OutputColumns {
1945    match expression {
1946        Expression::Select(select) => annotate_select(select, parent, dialect),
1947        Expression::Subquery(subquery) => {
1948            let columns = annotate_scoped_expression(&mut subquery.this, parent, dialect);
1949            if let Some((_, first_type)) = columns.first() {
1950                subquery.inferred_type = Some(first_type.clone());
1951            }
1952            columns
1953        }
1954        Expression::Cte(cte) => annotate_scoped_expression(&mut cte.this, parent, dialect),
1955        Expression::Paren(paren) => annotate_scoped_expression(&mut paren.this, parent, dialect),
1956        Expression::Union(union) => {
1957            let mut schema = ScopedSchema::new(parent, dialect);
1958            annotate_with(&mut union.with, &mut schema, dialect);
1959            let columns = annotate_scoped_expression(&mut union.left, Some(&schema), dialect);
1960            annotate_scoped_expression(&mut union.right, Some(&schema), dialect);
1961            columns
1962        }
1963        Expression::Intersect(intersect) => {
1964            let mut schema = ScopedSchema::new(parent, dialect);
1965            annotate_with(&mut intersect.with, &mut schema, dialect);
1966            let columns = annotate_scoped_expression(&mut intersect.left, Some(&schema), dialect);
1967            annotate_scoped_expression(&mut intersect.right, Some(&schema), dialect);
1968            columns
1969        }
1970        Expression::Except(except) => {
1971            let mut schema = ScopedSchema::new(parent, dialect);
1972            annotate_with(&mut except.with, &mut schema, dialect);
1973            let columns = annotate_scoped_expression(&mut except.left, Some(&schema), dialect);
1974            annotate_scoped_expression(&mut except.right, Some(&schema), dialect);
1975            columns
1976        }
1977        _ => {
1978            let mut annotator = TypeAnnotator::new(parent, dialect);
1979            annotator.annotate_in_place(expression);
1980            Vec::new()
1981        }
1982    }
1983}
1984
1985/// Annotate types in-place on the expression tree.
1986///
1987/// Walks the AST bottom-up and sets `inferred_type` on each value-producing
1988/// node. After this call, `expr.inferred_type()` (and the same on any child
1989/// node) returns the inferred type.
1990pub fn annotate_types(
1991    expr: &mut Expression,
1992    schema: Option<&dyn Schema>,
1993    dialect: Option<DialectType>,
1994) {
1995    annotate_scoped_expression(expr, schema, dialect);
1996}
1997
1998#[cfg(test)]
1999mod tests {
2000    use super::*;
2001    use crate::expressions::{BooleanLiteral, Cast, Null};
2002    use crate::{parse_one, DialectType, MappingSchema, Schema};
2003
2004    fn make_int_literal(val: i64) -> Expression {
2005        Expression::Literal(Box::new(Literal::Number(val.to_string())))
2006    }
2007
2008    fn make_float_literal(val: f64) -> Expression {
2009        Expression::Literal(Box::new(Literal::Number(val.to_string())))
2010    }
2011
2012    fn make_string_literal(val: &str) -> Expression {
2013        Expression::Literal(Box::new(Literal::String(val.to_string())))
2014    }
2015
2016    fn make_bool_literal(val: bool) -> Expression {
2017        Expression::Boolean(BooleanLiteral { value: val })
2018    }
2019
2020    #[test]
2021    fn test_literal_types() {
2022        let mut annotator = TypeAnnotator::new(None, None);
2023
2024        // Integer literal
2025        let int_expr = make_int_literal(42);
2026        assert_eq!(
2027            annotator.annotate(&int_expr),
2028            Some(DataType::Int {
2029                length: None,
2030                integer_spelling: false
2031            })
2032        );
2033
2034        // Float literal
2035        let float_expr = make_float_literal(3.14);
2036        assert_eq!(
2037            annotator.annotate(&float_expr),
2038            Some(DataType::Double {
2039                precision: None,
2040                scale: None
2041            })
2042        );
2043
2044        // String literal
2045        let string_expr = make_string_literal("hello");
2046        assert_eq!(
2047            annotator.annotate(&string_expr),
2048            Some(DataType::VarChar {
2049                length: None,
2050                parenthesized_length: false
2051            })
2052        );
2053
2054        // Boolean literal
2055        let bool_expr = make_bool_literal(true);
2056        assert_eq!(annotator.annotate(&bool_expr), Some(DataType::Boolean));
2057
2058        // Null literal
2059        let null_expr = Expression::Null(Null);
2060        assert_eq!(annotator.annotate(&null_expr), None);
2061    }
2062
2063    #[test]
2064    fn test_comparison_types() {
2065        let mut annotator = TypeAnnotator::new(None, None);
2066
2067        // Comparison returns boolean
2068        let cmp = Expression::Gt(Box::new(BinaryOp::new(
2069            make_int_literal(1),
2070            make_int_literal(2),
2071        )));
2072        assert_eq!(annotator.annotate(&cmp), Some(DataType::Boolean));
2073
2074        // Equality returns boolean
2075        let eq = Expression::Eq(Box::new(BinaryOp::new(
2076            make_string_literal("a"),
2077            make_string_literal("b"),
2078        )));
2079        assert_eq!(annotator.annotate(&eq), Some(DataType::Boolean));
2080    }
2081
2082    #[test]
2083    fn test_arithmetic_types() {
2084        let mut annotator = TypeAnnotator::new(None, None);
2085
2086        // Int + Int = Int
2087        let add_int = Expression::Add(Box::new(BinaryOp::new(
2088            make_int_literal(1),
2089            make_int_literal(2),
2090        )));
2091        assert_eq!(
2092            annotator.annotate(&add_int),
2093            Some(DataType::Int {
2094                length: None,
2095                integer_spelling: false
2096            })
2097        );
2098
2099        // Int + Float = Double (wider type)
2100        let add_mixed = Expression::Add(Box::new(BinaryOp::new(
2101            make_int_literal(1),
2102            make_float_literal(2.5), // Use 2.5 so the string has a decimal point
2103        )));
2104        assert_eq!(
2105            annotator.annotate(&add_mixed),
2106            Some(DataType::Double {
2107                precision: None,
2108                scale: None
2109            })
2110        );
2111    }
2112
2113    #[test]
2114    fn test_string_concat_type() {
2115        let mut annotator = TypeAnnotator::new(None, None);
2116
2117        // String || String = VarChar
2118        let concat = Expression::Concat(Box::new(BinaryOp::new(
2119            make_string_literal("hello"),
2120            make_string_literal(" world"),
2121        )));
2122        assert_eq!(
2123            annotator.annotate(&concat),
2124            Some(DataType::VarChar {
2125                length: None,
2126                parenthesized_length: false
2127            })
2128        );
2129    }
2130
2131    #[test]
2132    fn test_cast_type() {
2133        let mut annotator = TypeAnnotator::new(None, None);
2134
2135        // CAST(1 AS VARCHAR)
2136        let cast = Expression::Cast(Box::new(Cast {
2137            this: make_int_literal(1),
2138            to: DataType::VarChar {
2139                length: Some(10),
2140                parenthesized_length: false,
2141            },
2142            trailing_comments: vec![],
2143            double_colon_syntax: false,
2144            format: None,
2145            default: None,
2146            inferred_type: None,
2147        }));
2148        assert_eq!(
2149            annotator.annotate(&cast),
2150            Some(DataType::VarChar {
2151                length: Some(10),
2152                parenthesized_length: false
2153            })
2154        );
2155    }
2156
2157    #[test]
2158    fn test_function_types() {
2159        let mut annotator = TypeAnnotator::new(None, None);
2160
2161        // COUNT returns BigInt
2162        let count =
2163            Expression::Function(Box::new(Function::new("COUNT", vec![make_int_literal(1)])));
2164        assert_eq!(
2165            annotator.annotate(&count),
2166            Some(DataType::BigInt { length: None })
2167        );
2168
2169        // UPPER returns VarChar
2170        let upper = Expression::Function(Box::new(Function::new(
2171            "UPPER",
2172            vec![make_string_literal("hello")],
2173        )));
2174        assert_eq!(
2175            annotator.annotate(&upper),
2176            Some(DataType::VarChar {
2177                length: None,
2178                parenthesized_length: false
2179            })
2180        );
2181
2182        // NOW returns Timestamp
2183        let now = Expression::Function(Box::new(Function::new("NOW", vec![])));
2184        assert_eq!(
2185            annotator.annotate(&now),
2186            Some(DataType::Timestamp {
2187                precision: None,
2188                timezone: false
2189            })
2190        );
2191    }
2192
2193    #[test]
2194    fn test_duckdb_date_trunc_overload_types() {
2195        fn cast_to(data_type: DataType) -> Expression {
2196            Expression::Cast(Box::new(Cast {
2197                this: make_string_literal("value"),
2198                to: data_type,
2199                format: None,
2200                trailing_comments: Vec::new(),
2201                double_colon_syntax: false,
2202                default: None,
2203                inferred_type: None,
2204            }))
2205        }
2206
2207        fn date_trunc(value: Expression) -> Expression {
2208            Expression::Function(Box::new(Function::new(
2209                "DATE_TRUNC",
2210                vec![make_string_literal("month"), value],
2211            )))
2212        }
2213
2214        let mut annotator = TypeAnnotator::new(None, Some(DialectType::DuckDB));
2215
2216        for input_type in [
2217            DataType::Date,
2218            DataType::Timestamp {
2219                precision: Some(9),
2220                timezone: false,
2221            },
2222        ] {
2223            assert_eq!(
2224                annotator.annotate(&date_trunc(cast_to(input_type))),
2225                Some(DataType::Timestamp {
2226                    precision: None,
2227                    timezone: false,
2228                })
2229            );
2230        }
2231
2232        assert_eq!(
2233            annotator.annotate(&date_trunc(cast_to(DataType::Timestamp {
2234                precision: Some(6),
2235                timezone: true,
2236            }))),
2237            Some(DataType::Timestamp {
2238                precision: None,
2239                timezone: true,
2240            })
2241        );
2242        assert_eq!(
2243            annotator.annotate(&date_trunc(cast_to(DataType::Interval {
2244                unit: Some("DAY".to_string()),
2245                to: Some("SECOND".to_string()),
2246            }))),
2247            Some(DataType::Interval {
2248                unit: None,
2249                to: None,
2250            })
2251        );
2252        assert_eq!(
2253            annotator.annotate(&date_trunc(Expression::Null(Null))),
2254            None
2255        );
2256    }
2257
2258    #[test]
2259    fn test_coalesce_type_inference() {
2260        let mut annotator = TypeAnnotator::new(None, None);
2261
2262        // COALESCE(NULL, 1) returns Int (type of first non-null arg)
2263        let coalesce = Expression::Function(Box::new(Function::new(
2264            "COALESCE",
2265            vec![Expression::Null(Null), make_int_literal(1)],
2266        )));
2267        assert_eq!(
2268            annotator.annotate(&coalesce),
2269            Some(DataType::Int {
2270                length: None,
2271                integer_spelling: false
2272            })
2273        );
2274
2275        let specialized_coalesce = Expression::Coalesce(Box::new(crate::expressions::VarArgFunc {
2276            expressions: vec![Expression::Null(Null), make_int_literal(1)],
2277            original_name: None,
2278            inferred_type: None,
2279        }));
2280        assert_eq!(
2281            annotator.annotate(&specialized_coalesce),
2282            Some(DataType::Int {
2283                length: None,
2284                integer_spelling: false
2285            })
2286        );
2287    }
2288
2289    #[test]
2290    fn test_type_coercion_class() {
2291        // Text types
2292        assert_eq!(
2293            TypeCoercionClass::from_data_type(&DataType::VarChar {
2294                length: None,
2295                parenthesized_length: false
2296            }),
2297            Some(TypeCoercionClass::Text)
2298        );
2299        assert_eq!(
2300            TypeCoercionClass::from_data_type(&DataType::Text),
2301            Some(TypeCoercionClass::Text)
2302        );
2303
2304        // Numeric types
2305        assert_eq!(
2306            TypeCoercionClass::from_data_type(&DataType::Int {
2307                length: None,
2308                integer_spelling: false
2309            }),
2310            Some(TypeCoercionClass::Numeric)
2311        );
2312        assert_eq!(
2313            TypeCoercionClass::from_data_type(&DataType::Double {
2314                precision: None,
2315                scale: None
2316            }),
2317            Some(TypeCoercionClass::Numeric)
2318        );
2319
2320        // Timelike types
2321        assert_eq!(
2322            TypeCoercionClass::from_data_type(&DataType::Date),
2323            Some(TypeCoercionClass::Timelike)
2324        );
2325        assert_eq!(
2326            TypeCoercionClass::from_data_type(&DataType::Timestamp {
2327                precision: None,
2328                timezone: false
2329            }),
2330            Some(TypeCoercionClass::Timelike)
2331        );
2332
2333        // Unknown types
2334        assert_eq!(TypeCoercionClass::from_data_type(&DataType::Json), None);
2335    }
2336
2337    #[test]
2338    fn test_wider_numeric_type() {
2339        let annotator = TypeAnnotator::new(None, None);
2340
2341        // Int vs BigInt -> BigInt
2342        let result = annotator.wider_numeric_type(
2343            &DataType::Int {
2344                length: None,
2345                integer_spelling: false,
2346            },
2347            &DataType::BigInt { length: None },
2348        );
2349        assert_eq!(result, DataType::BigInt { length: None });
2350
2351        // Float vs Double -> Double
2352        let result = annotator.wider_numeric_type(
2353            &DataType::Float {
2354                precision: None,
2355                scale: None,
2356                real_spelling: false,
2357            },
2358            &DataType::Double {
2359                precision: None,
2360                scale: None,
2361            },
2362        );
2363        assert_eq!(
2364            result,
2365            DataType::Double {
2366                precision: None,
2367                scale: None
2368            }
2369        );
2370
2371        // Int vs Double -> Double
2372        let result = annotator.wider_numeric_type(
2373            &DataType::Int {
2374                length: None,
2375                integer_spelling: false,
2376            },
2377            &DataType::Double {
2378                precision: None,
2379                scale: None,
2380            },
2381        );
2382        assert_eq!(
2383            result,
2384            DataType::Double {
2385                precision: None,
2386                scale: None
2387            }
2388        );
2389    }
2390
2391    #[test]
2392    fn test_aggregate_return_types() {
2393        let mut annotator = TypeAnnotator::new(None, None);
2394
2395        // SUM(int) returns BigInt
2396        let sum_type = annotator.get_aggregate_return_type("SUM", &[make_int_literal(1)]);
2397        assert_eq!(sum_type, Some(DataType::BigInt { length: None }));
2398
2399        // AVG always returns Double
2400        let avg_type = annotator.get_aggregate_return_type("AVG", &[make_int_literal(1)]);
2401        assert_eq!(
2402            avg_type,
2403            Some(DataType::Double {
2404                precision: None,
2405                scale: None
2406            })
2407        );
2408
2409        // MIN/MAX preserve input type
2410        let min_type = annotator.get_aggregate_return_type("MIN", &[make_string_literal("a")]);
2411        assert_eq!(
2412            min_type,
2413            Some(DataType::VarChar {
2414                length: None,
2415                parenthesized_length: false
2416            })
2417        );
2418
2419        // DuckDB MIN/MAX(value, n) return a list of the input type.
2420        let top_n_type = annotator
2421            .get_aggregate_return_type("MAX", &[make_string_literal("a"), make_int_literal(2)]);
2422        assert_eq!(
2423            top_n_type,
2424            Some(DataType::Array {
2425                element_type: Box::new(DataType::VarChar {
2426                    length: None,
2427                    parenthesized_length: false,
2428                }),
2429                dimension: None,
2430            })
2431        );
2432    }
2433
2434    #[test]
2435    fn test_date_literal_types() {
2436        let mut annotator = TypeAnnotator::new(None, None);
2437
2438        // DATE literal
2439        let date_expr = Expression::Literal(Box::new(Literal::Date("2024-01-15".to_string())));
2440        assert_eq!(annotator.annotate(&date_expr), Some(DataType::Date));
2441
2442        // TIME literal
2443        let time_expr = Expression::Literal(Box::new(Literal::Time("10:30:00".to_string())));
2444        assert_eq!(
2445            annotator.annotate(&time_expr),
2446            Some(DataType::Time {
2447                precision: None,
2448                timezone: false
2449            })
2450        );
2451
2452        // TIMESTAMP literal
2453        let ts_expr = Expression::Literal(Box::new(Literal::Timestamp(
2454            "2024-01-15 10:30:00".to_string(),
2455        )));
2456        assert_eq!(
2457            annotator.annotate(&ts_expr),
2458            Some(DataType::Timestamp {
2459                precision: None,
2460                timezone: false
2461            })
2462        );
2463    }
2464
2465    #[test]
2466    fn test_logical_operations() {
2467        let mut annotator = TypeAnnotator::new(None, None);
2468
2469        // AND returns boolean
2470        let and_expr = Expression::And(Box::new(BinaryOp::new(
2471            make_bool_literal(true),
2472            make_bool_literal(false),
2473        )));
2474        assert_eq!(annotator.annotate(&and_expr), Some(DataType::Boolean));
2475
2476        // OR returns boolean
2477        let or_expr = Expression::Or(Box::new(BinaryOp::new(
2478            make_bool_literal(true),
2479            make_bool_literal(false),
2480        )));
2481        assert_eq!(annotator.annotate(&or_expr), Some(DataType::Boolean));
2482
2483        // NOT returns boolean
2484        let not_expr = Expression::Not(Box::new(crate::expressions::UnaryOp::new(
2485            make_bool_literal(true),
2486        )));
2487        assert_eq!(annotator.annotate(&not_expr), Some(DataType::Boolean));
2488    }
2489
2490    // ========================================
2491    // Tests for newly implemented features
2492    // ========================================
2493
2494    #[test]
2495    fn test_subscript_array_type() {
2496        let mut annotator = TypeAnnotator::new(None, None);
2497
2498        // Array[index] returns element type
2499        let arr = Expression::Array(Box::new(crate::expressions::Array {
2500            expressions: vec![make_int_literal(1), make_int_literal(2)],
2501        }));
2502        let subscript = Expression::Subscript(Box::new(crate::expressions::Subscript {
2503            this: arr,
2504            index: make_int_literal(0),
2505        }));
2506        assert_eq!(
2507            annotator.annotate(&subscript),
2508            Some(DataType::Int {
2509                length: None,
2510                integer_spelling: false
2511            })
2512        );
2513    }
2514
2515    #[test]
2516    fn test_subscript_map_type() {
2517        let mut annotator = TypeAnnotator::new(None, None);
2518
2519        // Map[key] returns value type
2520        let map = Expression::Map(Box::new(crate::expressions::Map {
2521            keys: vec![make_string_literal("a")],
2522            values: vec![make_int_literal(1)],
2523        }));
2524        let subscript = Expression::Subscript(Box::new(crate::expressions::Subscript {
2525            this: map,
2526            index: make_string_literal("a"),
2527        }));
2528        assert_eq!(
2529            annotator.annotate(&subscript),
2530            Some(DataType::Int {
2531                length: None,
2532                integer_spelling: false
2533            })
2534        );
2535    }
2536
2537    #[test]
2538    fn test_struct_type() {
2539        let mut annotator = TypeAnnotator::new(None, None);
2540
2541        // STRUCT literal
2542        let struct_expr = Expression::Struct(Box::new(crate::expressions::Struct {
2543            fields: vec![
2544                (Some("name".to_string()), make_string_literal("Alice")),
2545                (Some("age".to_string()), make_int_literal(30)),
2546            ],
2547        }));
2548        let result = annotator.annotate(&struct_expr);
2549        assert!(matches!(result, Some(DataType::Struct { fields, .. }) if fields.len() == 2));
2550    }
2551
2552    #[test]
2553    fn test_map_type() {
2554        let mut annotator = TypeAnnotator::new(None, None);
2555
2556        // MAP literal
2557        let map_expr = Expression::Map(Box::new(crate::expressions::Map {
2558            keys: vec![make_string_literal("a"), make_string_literal("b")],
2559            values: vec![make_int_literal(1), make_int_literal(2)],
2560        }));
2561        let result = annotator.annotate(&map_expr);
2562        assert!(matches!(
2563            result,
2564            Some(DataType::Map { key_type, value_type })
2565            if matches!(*key_type, DataType::VarChar { .. })
2566               && matches!(*value_type, DataType::Int { .. })
2567        ));
2568    }
2569
2570    #[test]
2571    fn test_explode_array_type() {
2572        let mut annotator = TypeAnnotator::new(None, None);
2573
2574        // EXPLODE(array) returns element type
2575        let arr = Expression::Array(Box::new(crate::expressions::Array {
2576            expressions: vec![make_int_literal(1), make_int_literal(2)],
2577        }));
2578        let explode = Expression::Explode(Box::new(crate::expressions::UnaryFunc {
2579            this: arr,
2580            original_name: None,
2581            inferred_type: None,
2582        }));
2583        assert_eq!(
2584            annotator.annotate(&explode),
2585            Some(DataType::Int {
2586                length: None,
2587                integer_spelling: false
2588            })
2589        );
2590    }
2591
2592    #[test]
2593    fn test_unnest_array_type() {
2594        let mut annotator = TypeAnnotator::new(None, None);
2595
2596        // UNNEST(array) returns element type
2597        let arr = Expression::Array(Box::new(crate::expressions::Array {
2598            expressions: vec![make_string_literal("a"), make_string_literal("b")],
2599        }));
2600        let unnest = Expression::Unnest(Box::new(crate::expressions::UnnestFunc {
2601            this: arr,
2602            expressions: Vec::new(),
2603            with_ordinality: false,
2604            alias: None,
2605            offset_alias: None,
2606            inferred_type: None,
2607        }));
2608        assert_eq!(
2609            annotator.annotate(&unnest),
2610            Some(DataType::VarChar {
2611                length: None,
2612                parenthesized_length: false
2613            })
2614        );
2615    }
2616
2617    #[test]
2618    fn test_set_operation_type() {
2619        let mut annotator = TypeAnnotator::new(None, None);
2620
2621        // UNION/INTERSECT/EXCEPT return None (they produce relations, not scalars)
2622        let select = Expression::Select(Box::new(crate::expressions::Select::default()));
2623        let union = Expression::Union(Box::new(crate::expressions::Union {
2624            left: select.clone(),
2625            right: select.clone(),
2626            all: false,
2627            distinct: false,
2628            with: None,
2629            order_by: None,
2630            limit: None,
2631            offset: None,
2632            by_name: false,
2633            side: None,
2634            kind: None,
2635            corresponding: false,
2636            strict: false,
2637            on_columns: Vec::new(),
2638            distribute_by: None,
2639            sort_by: None,
2640            cluster_by: None,
2641        }));
2642        assert_eq!(annotator.annotate(&union), None);
2643    }
2644
2645    #[test]
2646    fn test_floor_ceil_input_dependent_types() {
2647        use crate::expressions::{CeilFunc, FloorFunc};
2648
2649        let mut annotator = TypeAnnotator::new(None, None);
2650
2651        // FLOOR/CEIL with integer literal → Double (integers get promoted)
2652        let floor_int = Expression::Floor(Box::new(FloorFunc {
2653            this: make_int_literal(42),
2654            scale: None,
2655            to: None,
2656        }));
2657        assert_eq!(
2658            annotator.annotate(&floor_int),
2659            Some(DataType::Double {
2660                precision: None,
2661                scale: None,
2662            })
2663        );
2664
2665        let ceil_int = Expression::Ceil(Box::new(CeilFunc {
2666            this: make_int_literal(42),
2667            decimals: None,
2668            to: None,
2669        }));
2670        assert_eq!(
2671            annotator.annotate(&ceil_int),
2672            Some(DataType::Double {
2673                precision: None,
2674                scale: None,
2675            })
2676        );
2677
2678        // FLOOR with float literal → Double (literals are always Double)
2679        let floor_float = Expression::Floor(Box::new(FloorFunc {
2680            this: make_float_literal(3.14),
2681            scale: None,
2682            to: None,
2683        }));
2684        assert_eq!(
2685            annotator.annotate(&floor_float),
2686            Some(DataType::Double {
2687                precision: None,
2688                scale: None,
2689            })
2690        );
2691
2692        // FLOOR via Function("FLOOR") path → falls through to arg-based inference
2693        let floor_fn =
2694            Expression::Function(Box::new(Function::new("FLOOR", vec![make_int_literal(1)])));
2695        assert_eq!(
2696            annotator.annotate(&floor_fn),
2697            Some(DataType::Int {
2698                length: None,
2699                integer_spelling: false,
2700            })
2701        );
2702    }
2703
2704    #[test]
2705    fn test_sign_preserves_input_type() {
2706        use crate::expressions::UnaryFunc;
2707
2708        let mut annotator = TypeAnnotator::new(None, None);
2709
2710        // SIGN with integer literal → Int (preserves input type)
2711        let sign_int = Expression::Sign(Box::new(UnaryFunc {
2712            this: make_int_literal(42),
2713            original_name: None,
2714            inferred_type: None,
2715        }));
2716        assert_eq!(
2717            annotator.annotate(&sign_int),
2718            Some(DataType::Int {
2719                length: None,
2720                integer_spelling: false,
2721            })
2722        );
2723
2724        // SIGN with float literal → Double (preserves input type)
2725        let sign_float = Expression::Sign(Box::new(UnaryFunc {
2726            this: make_float_literal(3.14),
2727            original_name: None,
2728            inferred_type: None,
2729        }));
2730        assert_eq!(
2731            annotator.annotate(&sign_float),
2732            Some(DataType::Double {
2733                precision: None,
2734                scale: None,
2735            })
2736        );
2737
2738        // SIGN with a CAST to INT → Int (preserves input type)
2739        let sign_cast = Expression::Sign(Box::new(UnaryFunc {
2740            this: Expression::Cast(Box::new(Cast {
2741                this: make_int_literal(42),
2742                to: DataType::Int {
2743                    length: None,
2744                    integer_spelling: false,
2745                },
2746                format: None,
2747                trailing_comments: Vec::new(),
2748                double_colon_syntax: false,
2749                default: None,
2750                inferred_type: None,
2751            })),
2752            original_name: None,
2753            inferred_type: None,
2754        }));
2755        assert_eq!(
2756            annotator.annotate(&sign_cast),
2757            Some(DataType::Int {
2758                length: None,
2759                integer_spelling: false,
2760            })
2761        );
2762    }
2763
2764    #[test]
2765    fn test_date_format_types() {
2766        use crate::expressions::{DateFormatFunc, TimeToStr};
2767
2768        let mut annotator = TypeAnnotator::new(None, None);
2769
2770        // DateFormat → VarChar
2771        let date_fmt = Expression::DateFormat(Box::new(DateFormatFunc {
2772            this: make_string_literal("2024-01-01"),
2773            format: make_string_literal("%Y-%m-%d"),
2774        }));
2775        assert_eq!(
2776            annotator.annotate(&date_fmt),
2777            Some(DataType::VarChar {
2778                length: None,
2779                parenthesized_length: false,
2780            })
2781        );
2782
2783        // FormatDate → VarChar
2784        let format_date = Expression::FormatDate(Box::new(DateFormatFunc {
2785            this: make_string_literal("2024-01-01"),
2786            format: make_string_literal("%Y-%m-%d"),
2787        }));
2788        assert_eq!(
2789            annotator.annotate(&format_date),
2790            Some(DataType::VarChar {
2791                length: None,
2792                parenthesized_length: false,
2793            })
2794        );
2795
2796        // TimeToStr → VarChar
2797        let time_to_str = Expression::TimeToStr(Box::new(TimeToStr {
2798            this: Box::new(make_string_literal("2024-01-01")),
2799            format: "%Y-%m-%d".to_string(),
2800            culture: None,
2801            zone: None,
2802        }));
2803        assert_eq!(
2804            annotator.annotate(&time_to_str),
2805            Some(DataType::VarChar {
2806                length: None,
2807                parenthesized_length: false,
2808            })
2809        );
2810
2811        // DATE_FORMAT via Function path → VarChar (uses function_return_types)
2812        let date_fmt_fn = Expression::Function(Box::new(Function::new(
2813            "DATE_FORMAT",
2814            vec![
2815                make_string_literal("2024-01-01"),
2816                make_string_literal("%Y-%m-%d"),
2817            ],
2818        )));
2819        assert_eq!(
2820            annotator.annotate(&date_fmt_fn),
2821            Some(DataType::VarChar {
2822                length: None,
2823                parenthesized_length: false,
2824            })
2825        );
2826    }
2827
2828    // ===== In-place annotation tests (Step 9) =====
2829
2830    #[test]
2831    fn test_annotate_in_place_sets_type_on_root() {
2832        // Literals don't have inferred_type field, so test with a BinaryOp
2833        let mut expr = Expression::Add(Box::new(BinaryOp::new(
2834            make_int_literal(1),
2835            make_int_literal(2),
2836        )));
2837        annotate_types(&mut expr, None, None);
2838        assert_eq!(
2839            expr.inferred_type(),
2840            Some(&DataType::Int {
2841                length: None,
2842                integer_spelling: false,
2843            })
2844        );
2845    }
2846
2847    #[test]
2848    fn test_annotate_in_place_sets_types_on_children() {
2849        // (a + b) + (c - d) where all are ints
2850        // This tests that inner BinaryOp children also get annotated
2851        let inner_add = Expression::Add(Box::new(BinaryOp::new(
2852            make_int_literal(1),
2853            make_float_literal(2.5),
2854        )));
2855        let inner_sub = Expression::Sub(Box::new(BinaryOp::new(
2856            make_int_literal(3),
2857            make_int_literal(4),
2858        )));
2859        let mut expr = Expression::Add(Box::new(BinaryOp::new(inner_add, inner_sub)));
2860        annotate_types(&mut expr, None, None);
2861
2862        // Root (Add) should be Double (wider of Double and Int)
2863        assert_eq!(
2864            expr.inferred_type(),
2865            Some(&DataType::Double {
2866                precision: None,
2867                scale: None,
2868            })
2869        );
2870
2871        // Children should also have types
2872        if let Expression::Add(op) = &expr {
2873            // Left child (1 + 2.5) should be Double
2874            assert_eq!(
2875                op.left.inferred_type(),
2876                Some(&DataType::Double {
2877                    precision: None,
2878                    scale: None,
2879                })
2880            );
2881            // Right child (3 - 4) should be Int
2882            assert_eq!(
2883                op.right.inferred_type(),
2884                Some(&DataType::Int {
2885                    length: None,
2886                    integer_spelling: false,
2887                })
2888            );
2889        } else {
2890            panic!("Expected Add expression");
2891        }
2892    }
2893
2894    #[test]
2895    fn test_annotate_in_place_comparison() {
2896        let mut expr = Expression::Eq(Box::new(BinaryOp::new(
2897            make_int_literal(1),
2898            make_int_literal(2),
2899        )));
2900        annotate_types(&mut expr, None, None);
2901        assert_eq!(expr.inferred_type(), Some(&DataType::Boolean));
2902    }
2903
2904    #[test]
2905    fn test_annotate_in_place_cast() {
2906        let mut expr = Expression::Cast(Box::new(Cast {
2907            this: make_int_literal(42),
2908            to: DataType::VarChar {
2909                length: None,
2910                parenthesized_length: false,
2911            },
2912            trailing_comments: vec![],
2913            double_colon_syntax: false,
2914            format: None,
2915            default: None,
2916            inferred_type: None,
2917        }));
2918        annotate_types(&mut expr, None, None);
2919        assert_eq!(
2920            expr.inferred_type(),
2921            Some(&DataType::VarChar {
2922                length: None,
2923                parenthesized_length: false,
2924            })
2925        );
2926    }
2927
2928    #[test]
2929    fn test_annotate_in_place_nested_expression() {
2930        // (1 + 2) > 0  -> should be Boolean at root, Int for the Add
2931        let add = Expression::Add(Box::new(BinaryOp::new(
2932            make_int_literal(1),
2933            make_int_literal(2),
2934        )));
2935        let mut expr = Expression::Gt(Box::new(BinaryOp::new(add, make_int_literal(0))));
2936        annotate_types(&mut expr, None, None);
2937
2938        assert_eq!(expr.inferred_type(), Some(&DataType::Boolean));
2939
2940        // The left child (Add) should be Int
2941        if let Expression::Gt(op) = &expr {
2942            assert_eq!(
2943                op.left.inferred_type(),
2944                Some(&DataType::Int {
2945                    length: None,
2946                    integer_spelling: false,
2947                })
2948            );
2949        }
2950    }
2951
2952    #[test]
2953    fn test_annotate_in_place_parsed_sql() {
2954        use crate::parser::Parser;
2955        let mut expr =
2956            Parser::parse_sql("SELECT 1 + 2.0, 'hello', TRUE").expect("parse failed")[0].clone();
2957        annotate_types(&mut expr, None, None);
2958
2959        // The expression tree should have types annotated throughout
2960        // We can't easily inspect deep inside a parsed Select, but at minimum
2961        // the root Select itself won't have a type (it's not value-producing)
2962        assert!(expr.inferred_type().is_none());
2963    }
2964
2965    #[test]
2966    fn test_inferred_type_json_roundtrip() {
2967        let mut expr = Expression::Add(Box::new(BinaryOp::new(
2968            make_int_literal(1),
2969            make_int_literal(2),
2970        )));
2971        annotate_types(&mut expr, None, None);
2972
2973        // Serialize to JSON
2974        let json = serde_json::to_string(&expr).expect("serialize failed");
2975        // The JSON should contain the inferred_type
2976        assert!(json.contains("inferred_type"));
2977
2978        // Deserialize back
2979        let deserialized: Expression = serde_json::from_str(&json).expect("deserialize failed");
2980        assert_eq!(
2981            deserialized.inferred_type(),
2982            Some(&DataType::Int {
2983                length: None,
2984                integer_spelling: false,
2985            })
2986        );
2987    }
2988
2989    #[test]
2990    fn test_inferred_type_none_not_serialized() {
2991        // When inferred_type is None, it should not appear in JSON
2992        let expr = Expression::Add(Box::new(BinaryOp::new(
2993            make_int_literal(1),
2994            make_int_literal(2),
2995        )));
2996        let json = serde_json::to_string(&expr).expect("serialize failed");
2997        assert!(!json.contains("inferred_type"));
2998    }
2999
3000    #[test]
3001    fn test_annotate_if_func_bigquery_node_and_alias_type() {
3002        let mut schema = MappingSchema::with_dialect(DialectType::BigQuery);
3003        schema
3004            .add_table(
3005                "t",
3006                &[("col1".to_string(), DataType::String { length: None })],
3007                None,
3008            )
3009            .unwrap();
3010
3011        let mut expr = parse_one(
3012            "SELECT IF(col1 IS NOT NULL, 1, 0) AS x FROM t",
3013            DialectType::BigQuery,
3014        )
3015        .unwrap();
3016        annotate_types(&mut expr, Some(&schema), Some(DialectType::BigQuery));
3017
3018        let Expression::Select(select) = &expr else {
3019            panic!("expected select");
3020        };
3021        let Expression::Alias(alias) = &select.expressions[0] else {
3022            panic!("expected alias");
3023        };
3024
3025        assert_eq!(
3026            alias.this.inferred_type(),
3027            Some(&DataType::Int {
3028                length: None,
3029                integer_spelling: false,
3030            })
3031        );
3032        assert_eq!(
3033            select.expressions[0].inferred_type(),
3034            Some(&DataType::Int {
3035                length: None,
3036                integer_spelling: false,
3037            })
3038        );
3039    }
3040
3041    #[test]
3042    fn test_annotate_nvl2_node_type() {
3043        let mut expr = parse_one("SELECT NVL2(a, 1, 0) AS x", DialectType::Generic).unwrap();
3044        annotate_types(&mut expr, None, None);
3045
3046        let Expression::Select(select) = &expr else {
3047            panic!("expected select");
3048        };
3049        let Expression::Alias(alias) = &select.expressions[0] else {
3050            panic!("expected alias");
3051        };
3052
3053        assert_eq!(
3054            alias.this.inferred_type(),
3055            Some(&DataType::Int {
3056                length: None,
3057                integer_spelling: false,
3058            })
3059        );
3060    }
3061
3062    #[test]
3063    fn test_annotate_count_node_type() {
3064        let mut expr = parse_one("SELECT COUNT(1) AS x", DialectType::Generic).unwrap();
3065        annotate_types(&mut expr, None, None);
3066
3067        let Expression::Select(select) = &expr else {
3068            panic!("expected select");
3069        };
3070        let Expression::Alias(alias) = &select.expressions[0] else {
3071            panic!("expected alias");
3072        };
3073
3074        assert_eq!(
3075            alias.this.inferred_type(),
3076            Some(&DataType::BigInt { length: None })
3077        );
3078    }
3079
3080    #[test]
3081    fn test_annotate_group_concat_node_type() {
3082        let mut expr = parse_one("SELECT GROUP_CONCAT(a) AS x", DialectType::Generic).unwrap();
3083        annotate_types(&mut expr, None, None);
3084
3085        let Expression::Select(select) = &expr else {
3086            panic!("expected select");
3087        };
3088        let Expression::Alias(alias) = &select.expressions[0] else {
3089            panic!("expected alias");
3090        };
3091
3092        assert_eq!(
3093            alias.this.inferred_type(),
3094            Some(&DataType::VarChar {
3095                length: None,
3096                parenthesized_length: false,
3097            })
3098        );
3099    }
3100
3101    #[test]
3102    fn test_annotate_sum_if_generic_aggregate_type() {
3103        let mut expr =
3104            parse_one("SELECT SUM_IF(1, a > 0) AS x FROM t", DialectType::Generic).unwrap();
3105        annotate_types(&mut expr, None, None);
3106
3107        let Expression::Select(select) = &expr else {
3108            panic!("expected select");
3109        };
3110        let Expression::Alias(alias) = &select.expressions[0] else {
3111            panic!("expected alias");
3112        };
3113
3114        assert_eq!(
3115            select.expressions[0].inferred_type(),
3116            Some(&DataType::BigInt { length: None })
3117        );
3118        assert_eq!(
3119            alias.this.inferred_type(),
3120            Some(&DataType::BigInt { length: None })
3121        );
3122    }
3123}