Edit on GitHub

sqlglot.optimizer.annotate_types

  1from __future__ import annotations
  2
  3import functools
  4import logging
  5import typing as t
  6
  7from sqlglot import exp
  8from sqlglot.dialects.dialect import Dialect
  9from sqlglot.helper import (
 10    ensure_list,
 11    is_date_unit,
 12    is_iso_date,
 13    is_iso_datetime,
 14    seq_get,
 15)
 16from sqlglot.optimizer.scope import Scope, traverse_scope
 17from sqlglot.schema import MappingSchema, Schema, ensure_schema
 18
 19if t.TYPE_CHECKING:
 20    from sqlglot._typing import B, E
 21
 22    # TODO (mypyc): should be -> exp.DType but some coercion lambdas return DataType
 23    # (e.g. l.type). The original code used t.cast(exp.DType, ...) to satisfy mypy, but
 24    # mypyc enforces t.cast at runtime, rejecting DataType values. Widened to accept both.
 25    BinaryCoercionFunc = t.Callable[
 26        [exp.Expr, exp.Expr], t.Optional[t.Union[exp.DataType, exp.DType]]
 27    ]
 28    BinaryCoercions = dict[tuple[exp.DType, exp.DType], BinaryCoercionFunc]
 29
 30    from sqlglot.dialects.dialect import DialectType
 31    from sqlglot.typing import ExprMetadataType
 32
 33logger = logging.getLogger("sqlglot")
 34
 35# EXTRACT/DATE_PART specifiers that return BIGINT instead of INT
 36BIGINT_EXTRACT_DATE_PARTS = {
 37    "EPOCH_SECOND",
 38    "EPOCH_MILLISECOND",
 39    "EPOCH_MICROSECOND",
 40    "EPOCH_NANOSECOND",
 41    "NANOSECOND",
 42}
 43
 44
 45def annotate_types(
 46    expression: E,
 47    schema: dict[str, object] | Schema | None = None,
 48    expression_metadata: ExprMetadataType | None = None,
 49    coerces_to: dict[exp.DType, set[exp.DType]] | None = None,
 50    dialect: DialectType = None,
 51    overwrite_types: bool = True,
 52) -> E:
 53    """
 54    Infers the types of an expression, annotating its AST accordingly.
 55
 56    Example:
 57        >>> import sqlglot
 58        >>> schema = {"y": {"cola": "SMALLINT"}}
 59        >>> sql = "SELECT x.cola + 2.5 AS cola FROM (SELECT y.cola AS cola FROM y AS y) AS x"
 60        >>> annotated_expr = annotate_types(sqlglot.parse_one(sql), schema=schema)
 61        >>> annotated_expr.expressions[0].type.this  # Get the type of "x.cola + 2.5 AS cola"
 62        <DType.DOUBLE: 'DOUBLE'>
 63
 64    Args:
 65        expression: Expr to annotate.
 66        schema: Database schema.
 67        expression_metadata: Maps expression type to corresponding annotation function.
 68        coerces_to: Maps expression type to set of types that it can be coerced into.
 69        overwrite_types: Re-annotate the existing AST types.
 70
 71    Returns:
 72        The expression annotated with types.
 73    """
 74
 75    schema = ensure_schema(schema, dialect=dialect)
 76
 77    return TypeAnnotator(
 78        schema=schema,
 79        expression_metadata=expression_metadata,
 80        coerces_to=coerces_to,
 81        overwrite_types=overwrite_types,
 82    ).annotate(expression)
 83
 84
 85def _coerce_date_literal(l: exp.Expr, unit: exp.Expr | None) -> exp.DType:
 86    date_text = l.name
 87    is_iso_date_ = is_iso_date(date_text)
 88
 89    if is_iso_date_ and is_date_unit(unit):
 90        return exp.DType.DATE
 91
 92    # An ISO date is also an ISO datetime, but not vice versa
 93    if is_iso_date_ or is_iso_datetime(date_text):
 94        return exp.DType.DATETIME
 95
 96    return exp.DType.UNKNOWN
 97
 98
 99def _coerce_date(l: exp.Expr, unit: exp.Expr | None) -> exp.DType:
100    if not is_date_unit(unit):
101        return exp.DType.DATETIME
102    return l.type.this if l.type else exp.DType.UNKNOWN
103
104
105def swap_args(func: BinaryCoercionFunc) -> BinaryCoercionFunc:
106    @functools.wraps(func)
107    def _swapped(l: exp.Expr, r: exp.Expr) -> exp.DataType | exp.DType | None:
108        return func(r, l)
109
110    return _swapped
111
112
113def swap_all(coercions: BinaryCoercions) -> BinaryCoercions:
114    return {**coercions, **{(b, a): swap_args(func) for (a, b), func in coercions.items()}}
115
116
117def _build_coerces_to() -> dict[exp.DType, set[exp.DType]]:
118    # Highest-to-lowest type precedence, as specified in Spark's docs (ANSI):
119    # https://spark.apache.org/docs/3.2.0/sql-ref-ansi-compliance.html
120    text_precedence = (
121        exp.DType.TEXT,
122        exp.DType.NVARCHAR,
123        exp.DType.VARCHAR,
124        exp.DType.NCHAR,
125        exp.DType.CHAR,
126    )
127    numeric_precedence = (
128        exp.DType.DECFLOAT,
129        exp.DType.DOUBLE,
130        exp.DType.FLOAT,
131        exp.DType.BIGDECIMAL,
132        exp.DType.DECIMAL,
133        exp.DType.BIGINT,
134        exp.DType.INT,
135        exp.DType.SMALLINT,
136        exp.DType.TINYINT,
137    )
138    timelike_precedence = (
139        exp.DType.TIMESTAMPLTZ,
140        exp.DType.TIMESTAMPTZ,
141        exp.DType.TIMESTAMP,
142        exp.DType.DATETIME,
143        exp.DType.DATE,
144    )
145
146    result: dict[exp.DType, set[exp.DType]] = {}
147    for type_precedence in (text_precedence, numeric_precedence, timelike_precedence):
148        coerces_to: set[exp.DType] = set()
149        for data_type in type_precedence:
150            result[data_type] = coerces_to.copy()
151            coerces_to |= {data_type}
152    return result
153
154
155_COERCES_TO = _build_coerces_to()
156
157
158class TypeAnnotator:
159    NESTED_TYPES: t.ClassVar = {
160        exp.DType.ARRAY,
161    }
162
163    # Specifies what types a given type can be coerced into
164    COERCES_TO: t.ClassVar[dict[exp.DType, set[exp.DType]]] = _COERCES_TO
165
166    # Coercion functions for binary operations.
167    # Map of type pairs to a callable that takes both sides of the binary operation and returns the resulting type.
168    BINARY_COERCIONS: t.ClassVar = {
169        **swap_all(
170            {
171                (t, exp.DType.INTERVAL): lambda l, r: _coerce_date_literal(l, r.args.get("unit"))
172                for t in exp.DataType.TEXT_TYPES
173            }
174        ),
175        **swap_all(
176            {
177                # text + numeric will yield the numeric type to match most dialects' semantics
178                (text, numeric): lambda l, r: (
179                    l.type if l.type in exp.DataType.NUMERIC_TYPES else r.type
180                )
181                for text in exp.DataType.TEXT_TYPES
182                for numeric in exp.DataType.NUMERIC_TYPES
183            }
184        ),
185        **swap_all(
186            {
187                (exp.DType.DATE, exp.DType.INTERVAL): lambda l, r: _coerce_date(
188                    l, r.args.get("unit")
189                ),
190            }
191        ),
192    }
193
194    def __init__(
195        self,
196        schema: Schema,
197        expression_metadata: ExprMetadataType | None = None,
198        coerces_to: dict[exp.DType, set[exp.DType]] | None = None,
199        binary_coercions: BinaryCoercions | None = None,
200        overwrite_types: bool = True,
201    ) -> None:
202        self.schema = schema
203        dialect = schema.dialect or Dialect()
204        self.dialect = dialect
205        self.expression_metadata = expression_metadata or dialect.EXPRESSION_METADATA
206        self.coerces_to = coerces_to or dialect.COERCES_TO or self.COERCES_TO
207        self.binary_coercions = binary_coercions or self.BINARY_COERCIONS
208
209        # Caches the ids of annotated sub-Exprs, to ensure we only visit them once
210        self._visited: set[int] = set()
211
212        # Caches NULL-annotated expressions to set them to UNKNOWN after type inference is completed
213        self._null_expressions: dict[int, exp.Expr] = {}
214
215        # Databricks and Spark ≥v3 actually support NULL (i.e., VOID) as a type
216        self._supports_null_type = dialect.SUPPORTS_NULL_TYPE
217
218        # Maps an exp.SetOperation's id (e.g. UNION) to its projection types. This is computed if the
219        # exp.SetOperation is the expression of a scope source, as selecting from it multiple times
220        # would reprocess the entire subtree to coerce the types of its operands' projections
221        self._setop_column_types: dict[int, dict[str, exp.DataType | exp.DType]] = {}
222
223        # When set to False, this enables partial annotation by skipping already-annotated nodes
224        self._overwrite_types = overwrite_types
225
226        # Maps Scope to its corresponding selected sources
227        self._scope_selects: dict[Scope, dict[str, dict[str, t.Any]]] = {}
228
229    def clear(self) -> None:
230        self._visited.clear()
231        self._null_expressions.clear()
232        self._setop_column_types.clear()
233        self._scope_selects.clear()
234
235    # TODO (mypyc): should be expression: E -> E but mypyc resolves the TypeVar
236    # to the isinstance-narrowed type, causing runtime type check failures.
237    def _set_type(
238        self, expression: exp.Expr, target_type: exp.DataType | exp.DType | None
239    ) -> exp.Expr:
240        prev_type = expression.type
241        expression_id = id(expression)
242
243        # TODO (mypyc): expression.type = ... should work but mypyc compiles the property
244        # setter to enforce the getter's return type (Optional[DataType]), rejecting DType.
245        # Bypass by converting and assigning to _type directly.
246        dtype = target_type or exp.DType.UNKNOWN
247        expression._type = dtype if isinstance(dtype, exp.DataType) else exp.DataType.build(dtype)
248        self._visited.add(expression_id)
249
250        if (
251            not self._supports_null_type
252            and t.cast(exp.DataType, expression.type).this == exp.DType.NULL
253        ):
254            self._null_expressions[expression_id] = expression
255        elif prev_type and t.cast(exp.DataType, prev_type).this == exp.DType.NULL:
256            self._null_expressions.pop(expression_id, None)
257
258        return expression
259
260    def annotate(self, expression: E, annotate_scope: bool = True) -> E:
261        # This flag is used to avoid costly scope traversals when we only care about annotating
262        # non-column expressions (partial type inference), e.g., when simplifying in the optimizer
263        if annotate_scope:
264            for scope in traverse_scope(expression):
265                self.annotate_scope(scope)
266
267        # This takes care of non-traversable expressions
268        self._annotate_expression(expression)
269
270        # Replace NULL type with the default type of the targeted dialect, since the former is not an actual type;
271        # it is mostly used to aid type coercion, e.g. in query set operations.
272        # TODO (mypyc): uses list() + _set_type instead of direct expr.type = ... because
273        # mypyc's property setter bypass rejects DType, and _set_type modifies the dict.
274        for expr in list(self._null_expressions.values()):
275            self._set_type(expr, self.dialect.DEFAULT_NULL_TYPE)
276
277        return expression
278
279    def _get_scope_selects(self, scope: Scope) -> dict[str, dict[str, t.Any]]:
280        if scope not in self._scope_selects:
281            selects = {}
282            for name, source in scope.sources.items():
283                if not isinstance(source, Scope):
284                    continue
285
286                expression = source.expression
287                if isinstance(expression, exp.UDTF):
288                    values = []
289
290                    if isinstance(expression, exp.Lateral):
291                        if isinstance(expression.this, exp.Explode):
292                            values = [expression.this.this]
293                    elif isinstance(expression, exp.Unnest):
294                        values = [expression]
295                    elif not isinstance(expression, exp.TableFromRows):
296                        values = expression.expressions[0].expressions
297
298                    if not values:
299                        continue
300
301                    alias_column_names = expression.alias_column_names
302
303                    if (
304                        isinstance(expression, exp.Unnest)
305                        and expression.type
306                        and expression.type.is_type(exp.DType.STRUCT)
307                    ):
308                        selects[name] = {
309                            col_def.name: t.cast(t.Union[exp.DataType, exp.DType], col_def.kind)
310                            for col_def in expression.type.expressions
311                            if isinstance(col_def, exp.ColumnDef) and col_def.kind
312                        }
313                    else:
314                        selects[name] = {
315                            alias: column.type for alias, column in zip(alias_column_names, values)
316                        }
317                elif isinstance(expression, exp.SetOperation) and len(
318                    expression.left.selects
319                ) == len(expression.right.selects):
320                    selects[name] = self._get_setop_column_types(expression)
321                elif isinstance(expression, exp.Selectable):
322                    selects[name] = {s.alias_or_name: s.type for s in expression.selects if s.type}
323
324            self._scope_selects[scope] = selects
325
326        return self._scope_selects[scope]
327
328    def annotate_scope(self, scope: Scope) -> None:
329        if isinstance(self.schema, MappingSchema):
330            for table_column in scope.table_columns:
331                source = scope.sources.get(table_column.name)
332
333                if isinstance(source, exp.Table):
334                    schema = self.schema.find(
335                        source, raise_on_missing=False, ensure_data_types=True
336                    )
337                    if not isinstance(schema, dict):
338                        continue
339
340                    struct_type = exp.DataType(
341                        this=exp.DType.STRUCT,
342                        expressions=[
343                            exp.ColumnDef(this=exp.to_identifier(str(c)), kind=kind)
344                            for c, kind in schema.items()
345                        ],
346                        nested=True,
347                    )
348                    self._set_type(table_column, struct_type)
349                elif (
350                    isinstance(source, Scope)
351                    and isinstance(source.expression, exp.Query)
352                    and (
353                        source.expression.meta.get("query_type") or exp.DType.UNKNOWN.into_expr()
354                    ).is_type(exp.DType.STRUCT)
355                ):
356                    self._set_type(table_column, source.expression.meta["query_type"])
357
358        # Iterate through all the expressions of the current scope in post-order, and annotate
359        self._annotate_expression(scope.expression, scope)
360        self._fixup_order_by_aliases(scope)
361
362        if self.dialect.QUERY_RESULTS_ARE_STRUCTS and isinstance(scope.expression, exp.Query):
363            struct_type = exp.DataType(
364                this=exp.DType.STRUCT,
365                expressions=[
366                    exp.ColumnDef(
367                        this=exp.to_identifier(select.output_name),
368                        kind=select.type.copy() if select.type else None,
369                    )
370                    for select in scope.expression.selects
371                ],
372                nested=True,
373            )
374
375            if not any(
376                cd.kind.is_type(exp.DType.UNKNOWN) for cd in struct_type.expressions if cd.kind
377            ):
378                # We don't use `_set_type` on purpose here. If we annotated the query directly, then
379                # using it in other contexts (e.g., ARRAY(<query>)) could result in incorrect type
380                # annotations, i.e., it shouldn't be interpreted as a STRUCT value.
381                scope.expression.meta["query_type"] = struct_type
382
383    def _annotate_expression(
384        self,
385        expression: exp.Expr,
386        scope: Scope | None = None,
387    ) -> None:
388        stack = [(expression, False)]
389
390        while stack:
391            expr, children_annotated = stack.pop()
392
393            if id(expr) in self._visited or (
394                not self._overwrite_types and expr.type and not expr.is_type(exp.DType.UNKNOWN)
395            ):
396                continue  # We've already inferred the expression's type
397
398            if not children_annotated:
399                stack.append((expr, True))
400                for child_expr in expr.iter_expressions():
401                    stack.append((child_expr, False))
402                continue
403
404            if scope and isinstance(expr, exp.Column) and expr.table:
405                source = None
406                source_scope: Scope | None = scope
407                while source_scope and not source:
408                    source = source_scope.sources.get(expr.table)
409                    if not source:
410                        source_scope = source_scope.parent
411
412                if isinstance(source, exp.Table):
413                    self._set_type(expr, self.schema.get_column_type(source, expr))
414                elif source and source_scope:
415                    col_type = (
416                        self._get_scope_selects(source_scope).get(expr.table, {}).get(expr.name)
417                    )
418                    if col_type:
419                        self._set_type(expr, col_type)
420                    elif isinstance(source.expression, exp.Unnest):
421                        self._set_type(expr, source.expression.type)
422                    else:
423                        self._set_type(expr, exp.DType.UNKNOWN)
424                else:
425                    self._set_type(expr, exp.DType.UNKNOWN)
426
427                if expr.is_type(exp.DType.JSON) and (dot_parts := expr.meta.get("dot_parts")):
428                    # JSON dot access is case sensitive across all dialects, so we need to undo the normalization.
429                    i = iter(dot_parts)
430                    parent = expr.parent
431                    while isinstance(parent, exp.Dot):
432                        parent.expression.replace(exp.to_identifier(next(i), quoted=True))
433                        parent = parent.parent
434
435                    expr.meta.pop("dot_parts", None)
436
437                if expr.type and expr.type.args.get("nullable") is False:
438                    expr.meta["nonnull"] = True
439                continue
440
441            spec = self.expression_metadata.get(expr.__class__)
442
443            if spec and (annotator := spec.get("annotator")):
444                annotator(self, expr)
445            elif spec and (returns := spec.get("returns")):
446                self._set_type(expr, returns)
447            else:
448                self._set_type(expr, exp.DType.UNKNOWN)
449
450    def _fixup_order_by_aliases(self, scope: Scope) -> None:
451        query = scope.expression
452        if not isinstance(query, exp.Query):
453            return
454
455        order = query.args.get("order")
456        if not order:
457            return
458
459        # Build alias -> type map from fully-annotated projections (last match wins,
460        # consistent with how _expand_alias_refs handles duplicate aliases).
461        alias_types: dict[str, exp.DataType | exp.DType] = {}
462        for sel in query.selects:
463            if (
464                isinstance(sel, exp.Alias)
465                and sel.this.type
466                and not sel.this.is_type(exp.DType.UNKNOWN)
467            ):
468                alias_types[sel.alias] = sel.this.type
469
470        if not alias_types:
471            return
472
473        for ordered in order.expressions:
474            alias_cols = [
475                c for c in ordered.find_all(exp.Column) if not c.table and c.name in alias_types
476            ]
477            for col in alias_cols:
478                self._set_type(col, alias_types[col.name])
479
480            if alias_cols:
481                for node in ordered.walk(prune=lambda n: isinstance(n, exp.Subquery)):
482                    if not isinstance(node, (exp.Column, exp.Literal)):
483                        self._visited.discard(id(node))
484                self._annotate_expression(ordered, scope)
485
486    def _maybe_coerce(
487        self,
488        type1: exp.DataType | exp.DType,
489        type2: exp.DataType | exp.DType,
490    ) -> exp.DataType | exp.DType:
491        """
492        Returns type2 if type1 can be coerced into it, otherwise type1.
493
494        If either type is parameterized (e.g. DECIMAL(18, 2) contains two parameters),
495        we assume type1 does not coerce into type2, so we also return it in this case.
496        """
497        if isinstance(type1, exp.DataType):
498            if type1.expressions:
499                return type1
500            type1_value = type1.this
501        else:
502            type1_value = type1
503
504        if isinstance(type2, exp.DataType):
505            if type2.expressions:
506                return type2
507            type2_value = type2.this
508        else:
509            type2_value = type2
510
511        # We propagate the UNKNOWN type upwards if found
512        if exp.DType.UNKNOWN in (type1_value, type2_value):
513            return exp.DType.UNKNOWN
514
515        if type1_value == exp.DType.NULL:
516            return type2_value
517        if type2_value == exp.DType.NULL:
518            return type1_value
519
520        return type2_value if type2_value in self.coerces_to.get(type1_value, {}) else type1_value
521
522    def _get_setop_column_types(
523        self, setop: exp.SetOperation
524    ) -> dict[str, exp.DataType | exp.DType]:
525        """
526        Computes and returns the coerced column types for a SetOperation.
527
528        This handles UNION, INTERSECT, EXCEPT, etc., coercing types across
529        left and right operands for all projections/columns.
530
531        Args:
532            setop: The SetOperation expression to analyze
533
534        Returns:
535            Dictionary mapping column names to their coerced types
536        """
537        setop_id = id(setop)
538        if setop_id in self._setop_column_types:
539            return self._setop_column_types[setop_id]
540
541        col_types: dict[str, exp.DataType | exp.DType] = {}
542
543        # Validate that left and right have same number of projections
544        if not (
545            isinstance(setop, exp.SetOperation)
546            and setop.left.selects
547            and setop.right.selects
548            and len(setop.left.selects) == len(setop.right.selects)
549        ):
550            return col_types
551
552        # Process a chain / sub-tree of set operations
553        for set_op in setop.walk(
554            prune=lambda n: not isinstance(n, (exp.SetOperation, exp.Subquery))
555        ):
556            if not isinstance(set_op, exp.SetOperation):
557                continue
558
559            if set_op.args.get("by_name"):
560                r_type_by_select = {s.alias_or_name: s.type for s in set_op.right.selects}
561                setop_cols = {
562                    s.alias_or_name: self._maybe_coerce(
563                        t.cast(exp.DataType, s.type),
564                        r_type_by_select.get(s.alias_or_name) or exp.DType.UNKNOWN,
565                    )
566                    for s in set_op.left.selects
567                }
568            else:
569                setop_cols = {
570                    ls.alias_or_name: self._maybe_coerce(
571                        t.cast(exp.DataType, ls.type), t.cast(exp.DataType, rs.type)
572                    )
573                    for ls, rs in zip(set_op.left.selects, set_op.right.selects)
574                }
575
576            # Coerce intermediate results with the previously registered types, if they exist
577            for col_name, col_type in setop_cols.items():
578                col_types[col_name] = self._maybe_coerce(
579                    col_type, col_types.get(col_name, exp.DType.NULL)
580                )
581
582        self._setop_column_types[setop_id] = col_types
583        return col_types
584
585    def _annotate_binary(self, expression: B) -> B:
586        left, right = expression.left, expression.right
587        if not left or not right:
588            expression_sql = expression.sql(self.dialect)
589            logger.warning(f"Failed to annotate badly formed binary expression: {expression_sql}")
590            self._set_type(expression, None)
591            return expression
592
593        left_type, right_type = left.type.this, right.type.this  # type: ignore
594
595        # TODO (mypyc): should be isinstance(expression, (exp.Connector, exp.Predicate)) but
596        # mypyc narrows the variable to the first type in a tuple/or isinstance check when
597        # the types are sibling @trait classes, rejecting instances of the second type.
598        if issubclass(type(expression), (exp.Connector, exp.Predicate)):
599            self._set_type(expression, exp.DType.BOOLEAN)
600        elif (left_type, right_type) in self.binary_coercions:
601            self._set_type(expression, self.binary_coercions[(left_type, right_type)](left, right))
602        else:
603            self._annotate_by_args(expression, left, right)
604
605        if isinstance(expression, exp.Is) or (
606            left.meta.get("nonnull") is True and right.meta.get("nonnull") is True
607        ):
608            expression.meta["nonnull"] = True
609
610        return expression
611
612    def _annotate_unary(self, expression: E) -> E:
613        if isinstance(expression, exp.Not):
614            self._set_type(expression, exp.DType.BOOLEAN)
615        else:
616            self._set_type(expression, expression.this.type)
617
618        if expression.this.meta.get("nonnull") is True:
619            expression.meta["nonnull"] = True
620
621        return expression
622
623    def _annotate_literal(self, expression: exp.Literal) -> exp.Literal:
624        if expression.is_string:
625            self._set_type(expression, exp.DType.VARCHAR)
626        elif expression.is_int:
627            self._set_type(expression, exp.DType.INT)
628        else:
629            self._set_type(expression, exp.DType.DOUBLE)
630
631        expression.meta["nonnull"] = True
632
633        return expression
634
635    def _annotate_by_args(
636        self,
637        expression: E,
638        *args: str | exp.Expr,
639        promote: bool = False,
640        array: bool = False,
641    ) -> E:
642        literal_type = None
643        non_literal_type = None
644        nested_type = None
645
646        for arg in args:
647            if isinstance(arg, str):
648                expressions = expression.args.get(arg)
649            else:
650                expressions = arg
651
652            for expr in ensure_list(expressions):
653                expr_type = expr.type
654
655                if expr_type.is_type(exp.DType.UNKNOWN):
656                    self._set_type(expression, exp.DType.UNKNOWN)
657                    return expression
658
659                if nested_type:
660                    continue
661
662                # Stop coercing at the first nested data type found
663                if expr_type.args.get("nested"):
664                    nested_type = expr_type
665                elif isinstance(expr, exp.Literal):
666                    literal_type = self._maybe_coerce(literal_type or expr_type, expr_type)
667                else:
668                    non_literal_type = self._maybe_coerce(non_literal_type or expr_type, expr_type)
669
670        result_type = None
671
672        if nested_type:
673            result_type = nested_type
674        elif literal_type and non_literal_type:
675            if self.dialect.PRIORITIZE_NON_LITERAL_TYPES:
676                literal_this_type = (
677                    literal_type.this if isinstance(literal_type, exp.DataType) else literal_type
678                )
679                non_literal_this_type = (
680                    non_literal_type.this
681                    if isinstance(non_literal_type, exp.DataType)
682                    else non_literal_type
683                )
684                if (
685                    literal_this_type in exp.DataType.INTEGER_TYPES
686                    and non_literal_this_type in exp.DataType.INTEGER_TYPES
687                ) or (
688                    literal_this_type in exp.DataType.REAL_TYPES
689                    and non_literal_this_type in exp.DataType.REAL_TYPES
690                ):
691                    result_type = non_literal_type
692        else:
693            result_type = literal_type or non_literal_type or exp.DType.UNKNOWN
694
695        self._set_type(
696            expression,
697            result_type or self._maybe_coerce(non_literal_type, literal_type),  # type: ignore
698        )
699
700        if promote:
701            if expression.type.this in exp.DataType.INTEGER_TYPES:  # type: ignore
702                self._set_type(expression, exp.DType.BIGINT)
703            elif expression.type.this in exp.DataType.FLOAT_TYPES:  # type: ignore
704                self._set_type(expression, exp.DType.DOUBLE)
705
706        if array:
707            self._set_type(
708                expression,
709                exp.DataType(this=exp.DType.ARRAY, expressions=[expression.type], nested=True),
710            )
711
712        return expression
713
714    def _annotate_timeunit(
715        self, expression: exp.TimeUnit | exp.DateTrunc
716    ) -> exp.TimeUnit | exp.DateTrunc:
717        if expression.this.type.this in exp.DataType.TEXT_TYPES:
718            datatype = _coerce_date_literal(expression.this, expression.unit)
719        elif expression.this.type.this in exp.DataType.TEMPORAL_TYPES:
720            datatype = _coerce_date(expression.this, expression.unit)
721        else:
722            datatype = exp.DType.UNKNOWN
723
724        self._set_type(expression, datatype)
725        return expression
726
727    def _annotate_bracket(self, expression: exp.Bracket) -> exp.Bracket:
728        bracket_arg = expression.expressions[0]
729        this = expression.this
730
731        if isinstance(bracket_arg, exp.Slice):
732            self._set_type(expression, this.type)
733        elif this.type.is_type(exp.DType.ARRAY):
734            self._set_type(expression, seq_get(this.type.expressions, 0))
735        elif isinstance(this, (exp.Map, exp.VarMap)) and bracket_arg in this.keys:
736            index = this.keys.index(bracket_arg)
737            value = seq_get(this.values, index)
738            self._set_type(expression, value.type if value else None)
739        else:
740            self._set_type(expression, exp.DType.UNKNOWN)
741
742        return expression
743
744    def _annotate_div(self, expression: exp.Div) -> exp.Div:
745        left_type, right_type = expression.left.type.this, expression.right.type.this  # type: ignore
746
747        if (
748            expression.args.get("typed")
749            and left_type in exp.DataType.INTEGER_TYPES
750            and right_type in exp.DataType.INTEGER_TYPES
751        ):
752            self._set_type(expression, exp.DType.BIGINT)
753        else:
754            self._set_type(expression, self._maybe_coerce(left_type, right_type))
755            if expression.type and expression.type.this not in exp.DataType.REAL_TYPES:
756                self._set_type(expression, self._maybe_coerce(expression.type, exp.DType.DOUBLE))
757
758        return expression
759
760    def _annotate_dot(self, expression: exp.Dot) -> exp.Dot:
761        self._set_type(expression, None)
762
763        # Propagate type from qualified UDF calls (e.g., db.my_udf(...))
764        if isinstance(expression.expression, exp.Anonymous):
765            self._set_type(expression, expression.expression.type)
766            return expression
767
768        this_type = expression.this.type
769
770        if this_type and this_type.is_type(exp.DType.STRUCT):
771            for e in this_type.expressions:
772                if e.name == expression.expression.name:
773                    self._set_type(expression, e.kind)
774                    break
775
776        return expression
777
778    def _annotate_explode(self, expression: exp.Explode) -> exp.Explode:
779        self._set_type(expression, seq_get(expression.this.type.expressions, 0))
780        return expression
781
782    def _annotate_unnest(self, expression: exp.Unnest) -> exp.Unnest:
783        child = seq_get(expression.expressions, 0)
784
785        if child and child.is_type(exp.DType.ARRAY):
786            expr_type = seq_get(child.type.expressions, 0)
787        else:
788            expr_type = None
789
790        self._set_type(expression, expr_type)
791        return expression
792
793    def _annotate_subquery(self, expression: exp.Subquery) -> exp.Subquery:
794        # For scalar subqueries (subqueries with a single projection), infer the type
795        # from that single projection. This allows type propagation in cases like:
796        # SELECT (SELECT 1 AS c) AS c
797        query = expression.unnest()
798
799        if isinstance(query, exp.Query):
800            selects = query.selects
801            if len(selects) == 1:
802                self._set_type(expression, selects[0].type)
803                return expression
804
805        self._set_type(expression, exp.DType.UNKNOWN)
806        return expression
807
808    def _annotate_struct_value(self, expression: exp.Expr) -> exp.DataType | None | exp.ColumnDef:
809        # Case: STRUCT(key AS value)
810        this: exp.Expr | None = None
811        kind = expression.type
812
813        if alias := expression.args.get("alias"):
814            this = alias.copy()
815        elif expression.expression:
816            # Case: STRUCT(key = value) or STRUCT(key := value)
817            this = expression.this.copy()
818            kind = expression.expression.type
819        elif isinstance(expression, exp.Column):
820            # Case: STRUCT(c)
821            this = expression.this.copy()
822
823        if kind and kind.is_type(exp.DType.UNKNOWN):
824            return None
825
826        if this:
827            return exp.ColumnDef(this=this, kind=kind)
828
829        return kind
830
831    def _annotate_struct(self, expression: exp.Struct) -> exp.Struct:
832        expressions = []
833        for expr in expression.expressions:
834            struct_field_type = self._annotate_struct_value(expr)
835            if struct_field_type is None:
836                self._set_type(expression, None)
837                return expression
838
839            expressions.append(struct_field_type)
840
841        self._set_type(
842            expression,
843            exp.DataType(this=exp.DType.STRUCT, expressions=expressions, nested=True),
844        )
845        return expression
846
847    @t.overload
848    def _annotate_map(self, expression: exp.Map) -> exp.Map: ...
849
850    @t.overload
851    def _annotate_map(self, expression: exp.VarMap) -> exp.VarMap: ...
852
853    def _annotate_map(self, expression):
854        keys = expression.args.get("keys")
855        values = expression.args.get("values")
856
857        map_type = exp.DataType(this=exp.DType.MAP)
858        if isinstance(keys, exp.Array) and isinstance(values, exp.Array):
859            key_type = seq_get(keys.type.expressions, 0) or exp.DType.UNKNOWN
860            value_type = seq_get(values.type.expressions, 0) or exp.DType.UNKNOWN
861
862            if key_type != exp.DType.UNKNOWN and value_type != exp.DType.UNKNOWN:
863                map_type.set("expressions", [key_type, value_type])
864                map_type.set("nested", True)
865
866        self._set_type(expression, map_type)
867        return expression
868
869    def _annotate_to_map(self, expression: exp.ToMap) -> exp.ToMap:
870        map_type = exp.DataType(this=exp.DType.MAP)
871        arg = expression.this
872        if arg.is_type(exp.DType.STRUCT):
873            for coldef in arg.type.expressions:
874                kind = coldef.kind
875                if kind != exp.DType.UNKNOWN:
876                    map_type.set("expressions", [exp.DType.VARCHAR.into_expr(), kind])
877                    map_type.set("nested", True)
878                    break
879
880        self._set_type(expression, map_type)
881        return expression
882
883    def _annotate_extract(self, expression: exp.Extract) -> exp.Extract:
884        part = expression.name
885        if part == "TIME":
886            self._set_type(expression, exp.DType.TIME)
887        elif part == "DATE":
888            self._set_type(expression, exp.DType.DATE)
889        elif part in BIGINT_EXTRACT_DATE_PARTS:
890            self._set_type(expression, exp.DType.BIGINT)
891        else:
892            self._set_type(expression, exp.DType.INT)
893        return expression
894
895    def _annotate_by_array_element(self, expression: exp.Expr) -> exp.Expr:
896        array_arg = expression.this
897        if array_arg.type.is_type(exp.DType.ARRAY):
898            element_type = seq_get(array_arg.type.expressions, 0) or exp.DType.UNKNOWN
899            self._set_type(expression, element_type)
900        else:
901            self._set_type(expression, exp.DType.UNKNOWN)
902
903        return expression
logger = <Logger sqlglot (WARNING)>
BIGINT_EXTRACT_DATE_PARTS = {'EPOCH_MICROSECOND', 'NANOSECOND', 'EPOCH_NANOSECOND', 'EPOCH_MILLISECOND', 'EPOCH_SECOND'}
def annotate_types( expression: ~E, schema: dict[str, object] | sqlglot.schema.Schema | None = None, expression_metadata: dict[type[sqlglot.expressions.core.Expr], dict[str, typing.Any]] | None = None, coerces_to: dict[sqlglot.expressions.datatypes.DType, set[sqlglot.expressions.datatypes.DType]] | None = None, dialect: Union[str, sqlglot.dialects.Dialect, type[sqlglot.dialects.Dialect], NoneType] = None, overwrite_types: bool = True) -> ~E:
46def annotate_types(
47    expression: E,
48    schema: dict[str, object] | Schema | None = None,
49    expression_metadata: ExprMetadataType | None = None,
50    coerces_to: dict[exp.DType, set[exp.DType]] | None = None,
51    dialect: DialectType = None,
52    overwrite_types: bool = True,
53) -> E:
54    """
55    Infers the types of an expression, annotating its AST accordingly.
56
57    Example:
58        >>> import sqlglot
59        >>> schema = {"y": {"cola": "SMALLINT"}}
60        >>> sql = "SELECT x.cola + 2.5 AS cola FROM (SELECT y.cola AS cola FROM y AS y) AS x"
61        >>> annotated_expr = annotate_types(sqlglot.parse_one(sql), schema=schema)
62        >>> annotated_expr.expressions[0].type.this  # Get the type of "x.cola + 2.5 AS cola"
63        <DType.DOUBLE: 'DOUBLE'>
64
65    Args:
66        expression: Expr to annotate.
67        schema: Database schema.
68        expression_metadata: Maps expression type to corresponding annotation function.
69        coerces_to: Maps expression type to set of types that it can be coerced into.
70        overwrite_types: Re-annotate the existing AST types.
71
72    Returns:
73        The expression annotated with types.
74    """
75
76    schema = ensure_schema(schema, dialect=dialect)
77
78    return TypeAnnotator(
79        schema=schema,
80        expression_metadata=expression_metadata,
81        coerces_to=coerces_to,
82        overwrite_types=overwrite_types,
83    ).annotate(expression)

Infers the types of an expression, annotating its AST accordingly.

Example:
>>> import sqlglot
>>> schema = {"y": {"cola": "SMALLINT"}}
>>> sql = "SELECT x.cola + 2.5 AS cola FROM (SELECT y.cola AS cola FROM y AS y) AS x"
>>> annotated_expr = annotate_types(sqlglot.parse_one(sql), schema=schema)
>>> annotated_expr.expressions[0].type.this  # Get the type of "x.cola + 2.5 AS cola"
<DType.DOUBLE: 'DOUBLE'>
Arguments:
  • expression: Expr to annotate.
  • schema: Database schema.
  • expression_metadata: Maps expression type to corresponding annotation function.
  • coerces_to: Maps expression type to set of types that it can be coerced into.
  • overwrite_types: Re-annotate the existing AST types.
Returns:

The expression annotated with types.

106def swap_args(func: BinaryCoercionFunc) -> BinaryCoercionFunc:
107    @functools.wraps(func)
108    def _swapped(l: exp.Expr, r: exp.Expr) -> exp.DataType | exp.DType | None:
109        return func(r, l)
110
111    return _swapped
114def swap_all(coercions: BinaryCoercions) -> BinaryCoercions:
115    return {**coercions, **{(b, a): swap_args(func) for (a, b), func in coercions.items()}}
class TypeAnnotator:
159class TypeAnnotator:
160    NESTED_TYPES: t.ClassVar = {
161        exp.DType.ARRAY,
162    }
163
164    # Specifies what types a given type can be coerced into
165    COERCES_TO: t.ClassVar[dict[exp.DType, set[exp.DType]]] = _COERCES_TO
166
167    # Coercion functions for binary operations.
168    # Map of type pairs to a callable that takes both sides of the binary operation and returns the resulting type.
169    BINARY_COERCIONS: t.ClassVar = {
170        **swap_all(
171            {
172                (t, exp.DType.INTERVAL): lambda l, r: _coerce_date_literal(l, r.args.get("unit"))
173                for t in exp.DataType.TEXT_TYPES
174            }
175        ),
176        **swap_all(
177            {
178                # text + numeric will yield the numeric type to match most dialects' semantics
179                (text, numeric): lambda l, r: (
180                    l.type if l.type in exp.DataType.NUMERIC_TYPES else r.type
181                )
182                for text in exp.DataType.TEXT_TYPES
183                for numeric in exp.DataType.NUMERIC_TYPES
184            }
185        ),
186        **swap_all(
187            {
188                (exp.DType.DATE, exp.DType.INTERVAL): lambda l, r: _coerce_date(
189                    l, r.args.get("unit")
190                ),
191            }
192        ),
193    }
194
195    def __init__(
196        self,
197        schema: Schema,
198        expression_metadata: ExprMetadataType | None = None,
199        coerces_to: dict[exp.DType, set[exp.DType]] | None = None,
200        binary_coercions: BinaryCoercions | None = None,
201        overwrite_types: bool = True,
202    ) -> None:
203        self.schema = schema
204        dialect = schema.dialect or Dialect()
205        self.dialect = dialect
206        self.expression_metadata = expression_metadata or dialect.EXPRESSION_METADATA
207        self.coerces_to = coerces_to or dialect.COERCES_TO or self.COERCES_TO
208        self.binary_coercions = binary_coercions or self.BINARY_COERCIONS
209
210        # Caches the ids of annotated sub-Exprs, to ensure we only visit them once
211        self._visited: set[int] = set()
212
213        # Caches NULL-annotated expressions to set them to UNKNOWN after type inference is completed
214        self._null_expressions: dict[int, exp.Expr] = {}
215
216        # Databricks and Spark ≥v3 actually support NULL (i.e., VOID) as a type
217        self._supports_null_type = dialect.SUPPORTS_NULL_TYPE
218
219        # Maps an exp.SetOperation's id (e.g. UNION) to its projection types. This is computed if the
220        # exp.SetOperation is the expression of a scope source, as selecting from it multiple times
221        # would reprocess the entire subtree to coerce the types of its operands' projections
222        self._setop_column_types: dict[int, dict[str, exp.DataType | exp.DType]] = {}
223
224        # When set to False, this enables partial annotation by skipping already-annotated nodes
225        self._overwrite_types = overwrite_types
226
227        # Maps Scope to its corresponding selected sources
228        self._scope_selects: dict[Scope, dict[str, dict[str, t.Any]]] = {}
229
230    def clear(self) -> None:
231        self._visited.clear()
232        self._null_expressions.clear()
233        self._setop_column_types.clear()
234        self._scope_selects.clear()
235
236    # TODO (mypyc): should be expression: E -> E but mypyc resolves the TypeVar
237    # to the isinstance-narrowed type, causing runtime type check failures.
238    def _set_type(
239        self, expression: exp.Expr, target_type: exp.DataType | exp.DType | None
240    ) -> exp.Expr:
241        prev_type = expression.type
242        expression_id = id(expression)
243
244        # TODO (mypyc): expression.type = ... should work but mypyc compiles the property
245        # setter to enforce the getter's return type (Optional[DataType]), rejecting DType.
246        # Bypass by converting and assigning to _type directly.
247        dtype = target_type or exp.DType.UNKNOWN
248        expression._type = dtype if isinstance(dtype, exp.DataType) else exp.DataType.build(dtype)
249        self._visited.add(expression_id)
250
251        if (
252            not self._supports_null_type
253            and t.cast(exp.DataType, expression.type).this == exp.DType.NULL
254        ):
255            self._null_expressions[expression_id] = expression
256        elif prev_type and t.cast(exp.DataType, prev_type).this == exp.DType.NULL:
257            self._null_expressions.pop(expression_id, None)
258
259        return expression
260
261    def annotate(self, expression: E, annotate_scope: bool = True) -> E:
262        # This flag is used to avoid costly scope traversals when we only care about annotating
263        # non-column expressions (partial type inference), e.g., when simplifying in the optimizer
264        if annotate_scope:
265            for scope in traverse_scope(expression):
266                self.annotate_scope(scope)
267
268        # This takes care of non-traversable expressions
269        self._annotate_expression(expression)
270
271        # Replace NULL type with the default type of the targeted dialect, since the former is not an actual type;
272        # it is mostly used to aid type coercion, e.g. in query set operations.
273        # TODO (mypyc): uses list() + _set_type instead of direct expr.type = ... because
274        # mypyc's property setter bypass rejects DType, and _set_type modifies the dict.
275        for expr in list(self._null_expressions.values()):
276            self._set_type(expr, self.dialect.DEFAULT_NULL_TYPE)
277
278        return expression
279
280    def _get_scope_selects(self, scope: Scope) -> dict[str, dict[str, t.Any]]:
281        if scope not in self._scope_selects:
282            selects = {}
283            for name, source in scope.sources.items():
284                if not isinstance(source, Scope):
285                    continue
286
287                expression = source.expression
288                if isinstance(expression, exp.UDTF):
289                    values = []
290
291                    if isinstance(expression, exp.Lateral):
292                        if isinstance(expression.this, exp.Explode):
293                            values = [expression.this.this]
294                    elif isinstance(expression, exp.Unnest):
295                        values = [expression]
296                    elif not isinstance(expression, exp.TableFromRows):
297                        values = expression.expressions[0].expressions
298
299                    if not values:
300                        continue
301
302                    alias_column_names = expression.alias_column_names
303
304                    if (
305                        isinstance(expression, exp.Unnest)
306                        and expression.type
307                        and expression.type.is_type(exp.DType.STRUCT)
308                    ):
309                        selects[name] = {
310                            col_def.name: t.cast(t.Union[exp.DataType, exp.DType], col_def.kind)
311                            for col_def in expression.type.expressions
312                            if isinstance(col_def, exp.ColumnDef) and col_def.kind
313                        }
314                    else:
315                        selects[name] = {
316                            alias: column.type for alias, column in zip(alias_column_names, values)
317                        }
318                elif isinstance(expression, exp.SetOperation) and len(
319                    expression.left.selects
320                ) == len(expression.right.selects):
321                    selects[name] = self._get_setop_column_types(expression)
322                elif isinstance(expression, exp.Selectable):
323                    selects[name] = {s.alias_or_name: s.type for s in expression.selects if s.type}
324
325            self._scope_selects[scope] = selects
326
327        return self._scope_selects[scope]
328
329    def annotate_scope(self, scope: Scope) -> None:
330        if isinstance(self.schema, MappingSchema):
331            for table_column in scope.table_columns:
332                source = scope.sources.get(table_column.name)
333
334                if isinstance(source, exp.Table):
335                    schema = self.schema.find(
336                        source, raise_on_missing=False, ensure_data_types=True
337                    )
338                    if not isinstance(schema, dict):
339                        continue
340
341                    struct_type = exp.DataType(
342                        this=exp.DType.STRUCT,
343                        expressions=[
344                            exp.ColumnDef(this=exp.to_identifier(str(c)), kind=kind)
345                            for c, kind in schema.items()
346                        ],
347                        nested=True,
348                    )
349                    self._set_type(table_column, struct_type)
350                elif (
351                    isinstance(source, Scope)
352                    and isinstance(source.expression, exp.Query)
353                    and (
354                        source.expression.meta.get("query_type") or exp.DType.UNKNOWN.into_expr()
355                    ).is_type(exp.DType.STRUCT)
356                ):
357                    self._set_type(table_column, source.expression.meta["query_type"])
358
359        # Iterate through all the expressions of the current scope in post-order, and annotate
360        self._annotate_expression(scope.expression, scope)
361        self._fixup_order_by_aliases(scope)
362
363        if self.dialect.QUERY_RESULTS_ARE_STRUCTS and isinstance(scope.expression, exp.Query):
364            struct_type = exp.DataType(
365                this=exp.DType.STRUCT,
366                expressions=[
367                    exp.ColumnDef(
368                        this=exp.to_identifier(select.output_name),
369                        kind=select.type.copy() if select.type else None,
370                    )
371                    for select in scope.expression.selects
372                ],
373                nested=True,
374            )
375
376            if not any(
377                cd.kind.is_type(exp.DType.UNKNOWN) for cd in struct_type.expressions if cd.kind
378            ):
379                # We don't use `_set_type` on purpose here. If we annotated the query directly, then
380                # using it in other contexts (e.g., ARRAY(<query>)) could result in incorrect type
381                # annotations, i.e., it shouldn't be interpreted as a STRUCT value.
382                scope.expression.meta["query_type"] = struct_type
383
384    def _annotate_expression(
385        self,
386        expression: exp.Expr,
387        scope: Scope | None = None,
388    ) -> None:
389        stack = [(expression, False)]
390
391        while stack:
392            expr, children_annotated = stack.pop()
393
394            if id(expr) in self._visited or (
395                not self._overwrite_types and expr.type and not expr.is_type(exp.DType.UNKNOWN)
396            ):
397                continue  # We've already inferred the expression's type
398
399            if not children_annotated:
400                stack.append((expr, True))
401                for child_expr in expr.iter_expressions():
402                    stack.append((child_expr, False))
403                continue
404
405            if scope and isinstance(expr, exp.Column) and expr.table:
406                source = None
407                source_scope: Scope | None = scope
408                while source_scope and not source:
409                    source = source_scope.sources.get(expr.table)
410                    if not source:
411                        source_scope = source_scope.parent
412
413                if isinstance(source, exp.Table):
414                    self._set_type(expr, self.schema.get_column_type(source, expr))
415                elif source and source_scope:
416                    col_type = (
417                        self._get_scope_selects(source_scope).get(expr.table, {}).get(expr.name)
418                    )
419                    if col_type:
420                        self._set_type(expr, col_type)
421                    elif isinstance(source.expression, exp.Unnest):
422                        self._set_type(expr, source.expression.type)
423                    else:
424                        self._set_type(expr, exp.DType.UNKNOWN)
425                else:
426                    self._set_type(expr, exp.DType.UNKNOWN)
427
428                if expr.is_type(exp.DType.JSON) and (dot_parts := expr.meta.get("dot_parts")):
429                    # JSON dot access is case sensitive across all dialects, so we need to undo the normalization.
430                    i = iter(dot_parts)
431                    parent = expr.parent
432                    while isinstance(parent, exp.Dot):
433                        parent.expression.replace(exp.to_identifier(next(i), quoted=True))
434                        parent = parent.parent
435
436                    expr.meta.pop("dot_parts", None)
437
438                if expr.type and expr.type.args.get("nullable") is False:
439                    expr.meta["nonnull"] = True
440                continue
441
442            spec = self.expression_metadata.get(expr.__class__)
443
444            if spec and (annotator := spec.get("annotator")):
445                annotator(self, expr)
446            elif spec and (returns := spec.get("returns")):
447                self._set_type(expr, returns)
448            else:
449                self._set_type(expr, exp.DType.UNKNOWN)
450
451    def _fixup_order_by_aliases(self, scope: Scope) -> None:
452        query = scope.expression
453        if not isinstance(query, exp.Query):
454            return
455
456        order = query.args.get("order")
457        if not order:
458            return
459
460        # Build alias -> type map from fully-annotated projections (last match wins,
461        # consistent with how _expand_alias_refs handles duplicate aliases).
462        alias_types: dict[str, exp.DataType | exp.DType] = {}
463        for sel in query.selects:
464            if (
465                isinstance(sel, exp.Alias)
466                and sel.this.type
467                and not sel.this.is_type(exp.DType.UNKNOWN)
468            ):
469                alias_types[sel.alias] = sel.this.type
470
471        if not alias_types:
472            return
473
474        for ordered in order.expressions:
475            alias_cols = [
476                c for c in ordered.find_all(exp.Column) if not c.table and c.name in alias_types
477            ]
478            for col in alias_cols:
479                self._set_type(col, alias_types[col.name])
480
481            if alias_cols:
482                for node in ordered.walk(prune=lambda n: isinstance(n, exp.Subquery)):
483                    if not isinstance(node, (exp.Column, exp.Literal)):
484                        self._visited.discard(id(node))
485                self._annotate_expression(ordered, scope)
486
487    def _maybe_coerce(
488        self,
489        type1: exp.DataType | exp.DType,
490        type2: exp.DataType | exp.DType,
491    ) -> exp.DataType | exp.DType:
492        """
493        Returns type2 if type1 can be coerced into it, otherwise type1.
494
495        If either type is parameterized (e.g. DECIMAL(18, 2) contains two parameters),
496        we assume type1 does not coerce into type2, so we also return it in this case.
497        """
498        if isinstance(type1, exp.DataType):
499            if type1.expressions:
500                return type1
501            type1_value = type1.this
502        else:
503            type1_value = type1
504
505        if isinstance(type2, exp.DataType):
506            if type2.expressions:
507                return type2
508            type2_value = type2.this
509        else:
510            type2_value = type2
511
512        # We propagate the UNKNOWN type upwards if found
513        if exp.DType.UNKNOWN in (type1_value, type2_value):
514            return exp.DType.UNKNOWN
515
516        if type1_value == exp.DType.NULL:
517            return type2_value
518        if type2_value == exp.DType.NULL:
519            return type1_value
520
521        return type2_value if type2_value in self.coerces_to.get(type1_value, {}) else type1_value
522
523    def _get_setop_column_types(
524        self, setop: exp.SetOperation
525    ) -> dict[str, exp.DataType | exp.DType]:
526        """
527        Computes and returns the coerced column types for a SetOperation.
528
529        This handles UNION, INTERSECT, EXCEPT, etc., coercing types across
530        left and right operands for all projections/columns.
531
532        Args:
533            setop: The SetOperation expression to analyze
534
535        Returns:
536            Dictionary mapping column names to their coerced types
537        """
538        setop_id = id(setop)
539        if setop_id in self._setop_column_types:
540            return self._setop_column_types[setop_id]
541
542        col_types: dict[str, exp.DataType | exp.DType] = {}
543
544        # Validate that left and right have same number of projections
545        if not (
546            isinstance(setop, exp.SetOperation)
547            and setop.left.selects
548            and setop.right.selects
549            and len(setop.left.selects) == len(setop.right.selects)
550        ):
551            return col_types
552
553        # Process a chain / sub-tree of set operations
554        for set_op in setop.walk(
555            prune=lambda n: not isinstance(n, (exp.SetOperation, exp.Subquery))
556        ):
557            if not isinstance(set_op, exp.SetOperation):
558                continue
559
560            if set_op.args.get("by_name"):
561                r_type_by_select = {s.alias_or_name: s.type for s in set_op.right.selects}
562                setop_cols = {
563                    s.alias_or_name: self._maybe_coerce(
564                        t.cast(exp.DataType, s.type),
565                        r_type_by_select.get(s.alias_or_name) or exp.DType.UNKNOWN,
566                    )
567                    for s in set_op.left.selects
568                }
569            else:
570                setop_cols = {
571                    ls.alias_or_name: self._maybe_coerce(
572                        t.cast(exp.DataType, ls.type), t.cast(exp.DataType, rs.type)
573                    )
574                    for ls, rs in zip(set_op.left.selects, set_op.right.selects)
575                }
576
577            # Coerce intermediate results with the previously registered types, if they exist
578            for col_name, col_type in setop_cols.items():
579                col_types[col_name] = self._maybe_coerce(
580                    col_type, col_types.get(col_name, exp.DType.NULL)
581                )
582
583        self._setop_column_types[setop_id] = col_types
584        return col_types
585
586    def _annotate_binary(self, expression: B) -> B:
587        left, right = expression.left, expression.right
588        if not left or not right:
589            expression_sql = expression.sql(self.dialect)
590            logger.warning(f"Failed to annotate badly formed binary expression: {expression_sql}")
591            self._set_type(expression, None)
592            return expression
593
594        left_type, right_type = left.type.this, right.type.this  # type: ignore
595
596        # TODO (mypyc): should be isinstance(expression, (exp.Connector, exp.Predicate)) but
597        # mypyc narrows the variable to the first type in a tuple/or isinstance check when
598        # the types are sibling @trait classes, rejecting instances of the second type.
599        if issubclass(type(expression), (exp.Connector, exp.Predicate)):
600            self._set_type(expression, exp.DType.BOOLEAN)
601        elif (left_type, right_type) in self.binary_coercions:
602            self._set_type(expression, self.binary_coercions[(left_type, right_type)](left, right))
603        else:
604            self._annotate_by_args(expression, left, right)
605
606        if isinstance(expression, exp.Is) or (
607            left.meta.get("nonnull") is True and right.meta.get("nonnull") is True
608        ):
609            expression.meta["nonnull"] = True
610
611        return expression
612
613    def _annotate_unary(self, expression: E) -> E:
614        if isinstance(expression, exp.Not):
615            self._set_type(expression, exp.DType.BOOLEAN)
616        else:
617            self._set_type(expression, expression.this.type)
618
619        if expression.this.meta.get("nonnull") is True:
620            expression.meta["nonnull"] = True
621
622        return expression
623
624    def _annotate_literal(self, expression: exp.Literal) -> exp.Literal:
625        if expression.is_string:
626            self._set_type(expression, exp.DType.VARCHAR)
627        elif expression.is_int:
628            self._set_type(expression, exp.DType.INT)
629        else:
630            self._set_type(expression, exp.DType.DOUBLE)
631
632        expression.meta["nonnull"] = True
633
634        return expression
635
636    def _annotate_by_args(
637        self,
638        expression: E,
639        *args: str | exp.Expr,
640        promote: bool = False,
641        array: bool = False,
642    ) -> E:
643        literal_type = None
644        non_literal_type = None
645        nested_type = None
646
647        for arg in args:
648            if isinstance(arg, str):
649                expressions = expression.args.get(arg)
650            else:
651                expressions = arg
652
653            for expr in ensure_list(expressions):
654                expr_type = expr.type
655
656                if expr_type.is_type(exp.DType.UNKNOWN):
657                    self._set_type(expression, exp.DType.UNKNOWN)
658                    return expression
659
660                if nested_type:
661                    continue
662
663                # Stop coercing at the first nested data type found
664                if expr_type.args.get("nested"):
665                    nested_type = expr_type
666                elif isinstance(expr, exp.Literal):
667                    literal_type = self._maybe_coerce(literal_type or expr_type, expr_type)
668                else:
669                    non_literal_type = self._maybe_coerce(non_literal_type or expr_type, expr_type)
670
671        result_type = None
672
673        if nested_type:
674            result_type = nested_type
675        elif literal_type and non_literal_type:
676            if self.dialect.PRIORITIZE_NON_LITERAL_TYPES:
677                literal_this_type = (
678                    literal_type.this if isinstance(literal_type, exp.DataType) else literal_type
679                )
680                non_literal_this_type = (
681                    non_literal_type.this
682                    if isinstance(non_literal_type, exp.DataType)
683                    else non_literal_type
684                )
685                if (
686                    literal_this_type in exp.DataType.INTEGER_TYPES
687                    and non_literal_this_type in exp.DataType.INTEGER_TYPES
688                ) or (
689                    literal_this_type in exp.DataType.REAL_TYPES
690                    and non_literal_this_type in exp.DataType.REAL_TYPES
691                ):
692                    result_type = non_literal_type
693        else:
694            result_type = literal_type or non_literal_type or exp.DType.UNKNOWN
695
696        self._set_type(
697            expression,
698            result_type or self._maybe_coerce(non_literal_type, literal_type),  # type: ignore
699        )
700
701        if promote:
702            if expression.type.this in exp.DataType.INTEGER_TYPES:  # type: ignore
703                self._set_type(expression, exp.DType.BIGINT)
704            elif expression.type.this in exp.DataType.FLOAT_TYPES:  # type: ignore
705                self._set_type(expression, exp.DType.DOUBLE)
706
707        if array:
708            self._set_type(
709                expression,
710                exp.DataType(this=exp.DType.ARRAY, expressions=[expression.type], nested=True),
711            )
712
713        return expression
714
715    def _annotate_timeunit(
716        self, expression: exp.TimeUnit | exp.DateTrunc
717    ) -> exp.TimeUnit | exp.DateTrunc:
718        if expression.this.type.this in exp.DataType.TEXT_TYPES:
719            datatype = _coerce_date_literal(expression.this, expression.unit)
720        elif expression.this.type.this in exp.DataType.TEMPORAL_TYPES:
721            datatype = _coerce_date(expression.this, expression.unit)
722        else:
723            datatype = exp.DType.UNKNOWN
724
725        self._set_type(expression, datatype)
726        return expression
727
728    def _annotate_bracket(self, expression: exp.Bracket) -> exp.Bracket:
729        bracket_arg = expression.expressions[0]
730        this = expression.this
731
732        if isinstance(bracket_arg, exp.Slice):
733            self._set_type(expression, this.type)
734        elif this.type.is_type(exp.DType.ARRAY):
735            self._set_type(expression, seq_get(this.type.expressions, 0))
736        elif isinstance(this, (exp.Map, exp.VarMap)) and bracket_arg in this.keys:
737            index = this.keys.index(bracket_arg)
738            value = seq_get(this.values, index)
739            self._set_type(expression, value.type if value else None)
740        else:
741            self._set_type(expression, exp.DType.UNKNOWN)
742
743        return expression
744
745    def _annotate_div(self, expression: exp.Div) -> exp.Div:
746        left_type, right_type = expression.left.type.this, expression.right.type.this  # type: ignore
747
748        if (
749            expression.args.get("typed")
750            and left_type in exp.DataType.INTEGER_TYPES
751            and right_type in exp.DataType.INTEGER_TYPES
752        ):
753            self._set_type(expression, exp.DType.BIGINT)
754        else:
755            self._set_type(expression, self._maybe_coerce(left_type, right_type))
756            if expression.type and expression.type.this not in exp.DataType.REAL_TYPES:
757                self._set_type(expression, self._maybe_coerce(expression.type, exp.DType.DOUBLE))
758
759        return expression
760
761    def _annotate_dot(self, expression: exp.Dot) -> exp.Dot:
762        self._set_type(expression, None)
763
764        # Propagate type from qualified UDF calls (e.g., db.my_udf(...))
765        if isinstance(expression.expression, exp.Anonymous):
766            self._set_type(expression, expression.expression.type)
767            return expression
768
769        this_type = expression.this.type
770
771        if this_type and this_type.is_type(exp.DType.STRUCT):
772            for e in this_type.expressions:
773                if e.name == expression.expression.name:
774                    self._set_type(expression, e.kind)
775                    break
776
777        return expression
778
779    def _annotate_explode(self, expression: exp.Explode) -> exp.Explode:
780        self._set_type(expression, seq_get(expression.this.type.expressions, 0))
781        return expression
782
783    def _annotate_unnest(self, expression: exp.Unnest) -> exp.Unnest:
784        child = seq_get(expression.expressions, 0)
785
786        if child and child.is_type(exp.DType.ARRAY):
787            expr_type = seq_get(child.type.expressions, 0)
788        else:
789            expr_type = None
790
791        self._set_type(expression, expr_type)
792        return expression
793
794    def _annotate_subquery(self, expression: exp.Subquery) -> exp.Subquery:
795        # For scalar subqueries (subqueries with a single projection), infer the type
796        # from that single projection. This allows type propagation in cases like:
797        # SELECT (SELECT 1 AS c) AS c
798        query = expression.unnest()
799
800        if isinstance(query, exp.Query):
801            selects = query.selects
802            if len(selects) == 1:
803                self._set_type(expression, selects[0].type)
804                return expression
805
806        self._set_type(expression, exp.DType.UNKNOWN)
807        return expression
808
809    def _annotate_struct_value(self, expression: exp.Expr) -> exp.DataType | None | exp.ColumnDef:
810        # Case: STRUCT(key AS value)
811        this: exp.Expr | None = None
812        kind = expression.type
813
814        if alias := expression.args.get("alias"):
815            this = alias.copy()
816        elif expression.expression:
817            # Case: STRUCT(key = value) or STRUCT(key := value)
818            this = expression.this.copy()
819            kind = expression.expression.type
820        elif isinstance(expression, exp.Column):
821            # Case: STRUCT(c)
822            this = expression.this.copy()
823
824        if kind and kind.is_type(exp.DType.UNKNOWN):
825            return None
826
827        if this:
828            return exp.ColumnDef(this=this, kind=kind)
829
830        return kind
831
832    def _annotate_struct(self, expression: exp.Struct) -> exp.Struct:
833        expressions = []
834        for expr in expression.expressions:
835            struct_field_type = self._annotate_struct_value(expr)
836            if struct_field_type is None:
837                self._set_type(expression, None)
838                return expression
839
840            expressions.append(struct_field_type)
841
842        self._set_type(
843            expression,
844            exp.DataType(this=exp.DType.STRUCT, expressions=expressions, nested=True),
845        )
846        return expression
847
848    @t.overload
849    def _annotate_map(self, expression: exp.Map) -> exp.Map: ...
850
851    @t.overload
852    def _annotate_map(self, expression: exp.VarMap) -> exp.VarMap: ...
853
854    def _annotate_map(self, expression):
855        keys = expression.args.get("keys")
856        values = expression.args.get("values")
857
858        map_type = exp.DataType(this=exp.DType.MAP)
859        if isinstance(keys, exp.Array) and isinstance(values, exp.Array):
860            key_type = seq_get(keys.type.expressions, 0) or exp.DType.UNKNOWN
861            value_type = seq_get(values.type.expressions, 0) or exp.DType.UNKNOWN
862
863            if key_type != exp.DType.UNKNOWN and value_type != exp.DType.UNKNOWN:
864                map_type.set("expressions", [key_type, value_type])
865                map_type.set("nested", True)
866
867        self._set_type(expression, map_type)
868        return expression
869
870    def _annotate_to_map(self, expression: exp.ToMap) -> exp.ToMap:
871        map_type = exp.DataType(this=exp.DType.MAP)
872        arg = expression.this
873        if arg.is_type(exp.DType.STRUCT):
874            for coldef in arg.type.expressions:
875                kind = coldef.kind
876                if kind != exp.DType.UNKNOWN:
877                    map_type.set("expressions", [exp.DType.VARCHAR.into_expr(), kind])
878                    map_type.set("nested", True)
879                    break
880
881        self._set_type(expression, map_type)
882        return expression
883
884    def _annotate_extract(self, expression: exp.Extract) -> exp.Extract:
885        part = expression.name
886        if part == "TIME":
887            self._set_type(expression, exp.DType.TIME)
888        elif part == "DATE":
889            self._set_type(expression, exp.DType.DATE)
890        elif part in BIGINT_EXTRACT_DATE_PARTS:
891            self._set_type(expression, exp.DType.BIGINT)
892        else:
893            self._set_type(expression, exp.DType.INT)
894        return expression
895
896    def _annotate_by_array_element(self, expression: exp.Expr) -> exp.Expr:
897        array_arg = expression.this
898        if array_arg.type.is_type(exp.DType.ARRAY):
899            element_type = seq_get(array_arg.type.expressions, 0) or exp.DType.UNKNOWN
900            self._set_type(expression, element_type)
901        else:
902            self._set_type(expression, exp.DType.UNKNOWN)
903
904        return expression
TypeAnnotator( schema: sqlglot.schema.Schema, expression_metadata: dict[type[sqlglot.expressions.core.Expr], dict[str, typing.Any]] | None = None, coerces_to: dict[sqlglot.expressions.datatypes.DType, set[sqlglot.expressions.datatypes.DType]] | None = None, binary_coercions: dict[tuple[sqlglot.expressions.datatypes.DType, sqlglot.expressions.datatypes.DType], typing.Callable[[sqlglot.expressions.core.Expr, sqlglot.expressions.core.Expr], typing.Union[sqlglot.expressions.datatypes.DataType, sqlglot.expressions.datatypes.DType, NoneType]]] | None = None, overwrite_types: bool = True)
195    def __init__(
196        self,
197        schema: Schema,
198        expression_metadata: ExprMetadataType | None = None,
199        coerces_to: dict[exp.DType, set[exp.DType]] | None = None,
200        binary_coercions: BinaryCoercions | None = None,
201        overwrite_types: bool = True,
202    ) -> None:
203        self.schema = schema
204        dialect = schema.dialect or Dialect()
205        self.dialect = dialect
206        self.expression_metadata = expression_metadata or dialect.EXPRESSION_METADATA
207        self.coerces_to = coerces_to or dialect.COERCES_TO or self.COERCES_TO
208        self.binary_coercions = binary_coercions or self.BINARY_COERCIONS
209
210        # Caches the ids of annotated sub-Exprs, to ensure we only visit them once
211        self._visited: set[int] = set()
212
213        # Caches NULL-annotated expressions to set them to UNKNOWN after type inference is completed
214        self._null_expressions: dict[int, exp.Expr] = {}
215
216        # Databricks and Spark ≥v3 actually support NULL (i.e., VOID) as a type
217        self._supports_null_type = dialect.SUPPORTS_NULL_TYPE
218
219        # Maps an exp.SetOperation's id (e.g. UNION) to its projection types. This is computed if the
220        # exp.SetOperation is the expression of a scope source, as selecting from it multiple times
221        # would reprocess the entire subtree to coerce the types of its operands' projections
222        self._setop_column_types: dict[int, dict[str, exp.DataType | exp.DType]] = {}
223
224        # When set to False, this enables partial annotation by skipping already-annotated nodes
225        self._overwrite_types = overwrite_types
226
227        # Maps Scope to its corresponding selected sources
228        self._scope_selects: dict[Scope, dict[str, dict[str, t.Any]]] = {}
NESTED_TYPES: ClassVar = {<DType.ARRAY: 'ARRAY'>}
COERCES_TO: ClassVar[dict[sqlglot.expressions.datatypes.DType, set[sqlglot.expressions.datatypes.DType]]] = {<DType.TEXT: 'TEXT'>: set(), <DType.NVARCHAR: 'NVARCHAR'>: {<DType.TEXT: 'TEXT'>}, <DType.VARCHAR: 'VARCHAR'>: {<DType.TIME: 'TIME'>, <DType.DATETIME: 'DATETIME'>, <DType.TIMESTAMP: 'TIMESTAMP'>, <DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <DType.DATE: 'DATE'>, <DType.TEXT: 'TEXT'>, <DType.NVARCHAR: 'NVARCHAR'>}, <DType.NCHAR: 'NCHAR'>: {<DType.VARCHAR: 'VARCHAR'>, <DType.TEXT: 'TEXT'>, <DType.NVARCHAR: 'NVARCHAR'>}, <DType.CHAR: 'CHAR'>: {<DType.VARCHAR: 'VARCHAR'>, <DType.NCHAR: 'NCHAR'>, <DType.TEXT: 'TEXT'>, <DType.NVARCHAR: 'NVARCHAR'>}, <DType.DECFLOAT: 'DECFLOAT'>: set(), <DType.DOUBLE: 'DOUBLE'>: {<DType.DECFLOAT: 'DECFLOAT'>}, <DType.FLOAT: 'FLOAT'>: {<DType.DOUBLE: 'DOUBLE'>, <DType.DECFLOAT: 'DECFLOAT'>}, <DType.BIGDECIMAL: 'BIGDECIMAL'>: {<DType.DOUBLE: 'DOUBLE'>, <DType.DECFLOAT: 'DECFLOAT'>, <DType.FLOAT: 'FLOAT'>}, <DType.DECIMAL: 'DECIMAL'>: {<DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.FLOAT: 'FLOAT'>, <DType.DOUBLE: 'DOUBLE'>, <DType.DECFLOAT: 'DECFLOAT'>}, <DType.BIGINT: 'BIGINT'>: {<DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.FLOAT: 'FLOAT'>, <DType.DOUBLE: 'DOUBLE'>, <DType.DECFLOAT: 'DECFLOAT'>, <DType.DECIMAL: 'DECIMAL'>}, <DType.INT: 'INT'>: {<DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.BIGINT: 'BIGINT'>, <DType.FLOAT: 'FLOAT'>, <DType.DOUBLE: 'DOUBLE'>, <DType.DECFLOAT: 'DECFLOAT'>, <DType.DECIMAL: 'DECIMAL'>}, <DType.SMALLINT: 'SMALLINT'>: {<DType.INT: 'INT'>, <DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.BIGINT: 'BIGINT'>, <DType.FLOAT: 'FLOAT'>, <DType.DOUBLE: 'DOUBLE'>, <DType.DECFLOAT: 'DECFLOAT'>, <DType.DECIMAL: 'DECIMAL'>}, <DType.TINYINT: 'TINYINT'>: {<DType.FLOAT: 'FLOAT'>, <DType.INT: 'INT'>, <DType.SMALLINT: 'SMALLINT'>, <DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.BIGINT: 'BIGINT'>, <DType.DOUBLE: 'DOUBLE'>, <DType.DECFLOAT: 'DECFLOAT'>, <DType.DECIMAL: 'DECIMAL'>}, <DType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>: set(), <DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>: {<DType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>}, <DType.TIMESTAMP: 'TIMESTAMP'>: {<DType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>}, <DType.DATETIME: 'DATETIME'>: {<DType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <DType.TIMESTAMP: 'TIMESTAMP'>, <DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>}, <DType.DATE: 'DATE'>: {<DType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <DType.TIMESTAMP: 'TIMESTAMP'>, <DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <DType.DATETIME: 'DATETIME'>}}
BINARY_COERCIONS: ClassVar = {(<DType.VARCHAR: 'VARCHAR'>, <DType.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INTERVAL: 'INTERVAL'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INTERVAL: 'INTERVAL'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INTERVAL: 'INTERVAL'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INTERVAL: 'INTERVAL'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INTERVAL: 'INTERVAL'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INTERVAL: 'INTERVAL'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.DECFLOAT: 'DECFLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.DECFLOAT: 'DECFLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.DECFLOAT: 'DECFLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.DECFLOAT: 'DECFLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.DECFLOAT: 'DECFLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.DECFLOAT: 'DECFLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDECIMAL: 'UDECIMAL'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UTINYINT: 'UTINYINT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGINT: 'BIGINT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT128: 'INT128'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UMEDIUMINT: 'UMEDIUMINT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL: 'DECIMAL'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MONEY: 'MONEY'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDOUBLE: 'UDOUBLE'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TINYINT: 'TINYINT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UBIGINT: 'UBIGINT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT: 'INT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLINT: 'SMALLINT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL256: 'DECIMAL256'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL128: 'DECIMAL128'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIT: 'BIT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DOUBLE: 'DOUBLE'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT: 'UINT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT256: 'INT256'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLMONEY: 'SMALLMONEY'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.USMALLINT: 'USMALLINT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MEDIUMINT: 'MEDIUMINT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT128: 'UINT128'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL64: 'DECIMAL64'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.FLOAT: 'FLOAT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL32: 'DECIMAL32'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT256: 'UINT256'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECFLOAT: 'DECFLOAT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDECIMAL: 'UDECIMAL'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UTINYINT: 'UTINYINT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGINT: 'BIGINT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT128: 'INT128'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UMEDIUMINT: 'UMEDIUMINT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL: 'DECIMAL'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MONEY: 'MONEY'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDOUBLE: 'UDOUBLE'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TINYINT: 'TINYINT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UBIGINT: 'UBIGINT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT: 'INT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLINT: 'SMALLINT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL256: 'DECIMAL256'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL128: 'DECIMAL128'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIT: 'BIT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DOUBLE: 'DOUBLE'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT: 'UINT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT256: 'INT256'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLMONEY: 'SMALLMONEY'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.USMALLINT: 'USMALLINT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MEDIUMINT: 'MEDIUMINT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT128: 'UINT128'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL64: 'DECIMAL64'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.FLOAT: 'FLOAT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL32: 'DECIMAL32'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT256: 'UINT256'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECFLOAT: 'DECFLOAT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDECIMAL: 'UDECIMAL'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UTINYINT: 'UTINYINT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGINT: 'BIGINT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT128: 'INT128'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UMEDIUMINT: 'UMEDIUMINT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL: 'DECIMAL'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MONEY: 'MONEY'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDOUBLE: 'UDOUBLE'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TINYINT: 'TINYINT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UBIGINT: 'UBIGINT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT: 'INT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLINT: 'SMALLINT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL256: 'DECIMAL256'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL128: 'DECIMAL128'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIT: 'BIT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DOUBLE: 'DOUBLE'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT: 'UINT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT256: 'INT256'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLMONEY: 'SMALLMONEY'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.USMALLINT: 'USMALLINT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MEDIUMINT: 'MEDIUMINT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT128: 'UINT128'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL64: 'DECIMAL64'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.FLOAT: 'FLOAT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL32: 'DECIMAL32'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT256: 'UINT256'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECFLOAT: 'DECFLOAT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDECIMAL: 'UDECIMAL'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UTINYINT: 'UTINYINT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGINT: 'BIGINT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT128: 'INT128'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UMEDIUMINT: 'UMEDIUMINT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL: 'DECIMAL'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MONEY: 'MONEY'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDOUBLE: 'UDOUBLE'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TINYINT: 'TINYINT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UBIGINT: 'UBIGINT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT: 'INT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLINT: 'SMALLINT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL256: 'DECIMAL256'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL128: 'DECIMAL128'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIT: 'BIT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DOUBLE: 'DOUBLE'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT: 'UINT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT256: 'INT256'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLMONEY: 'SMALLMONEY'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.USMALLINT: 'USMALLINT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MEDIUMINT: 'MEDIUMINT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT128: 'UINT128'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL64: 'DECIMAL64'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.FLOAT: 'FLOAT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL32: 'DECIMAL32'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT256: 'UINT256'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECFLOAT: 'DECFLOAT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDECIMAL: 'UDECIMAL'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UTINYINT: 'UTINYINT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGINT: 'BIGINT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT128: 'INT128'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UMEDIUMINT: 'UMEDIUMINT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL: 'DECIMAL'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MONEY: 'MONEY'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDOUBLE: 'UDOUBLE'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TINYINT: 'TINYINT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UBIGINT: 'UBIGINT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT: 'INT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLINT: 'SMALLINT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL256: 'DECIMAL256'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL128: 'DECIMAL128'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIT: 'BIT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DOUBLE: 'DOUBLE'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT: 'UINT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT256: 'INT256'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLMONEY: 'SMALLMONEY'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.USMALLINT: 'USMALLINT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MEDIUMINT: 'MEDIUMINT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT128: 'UINT128'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL64: 'DECIMAL64'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.FLOAT: 'FLOAT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL32: 'DECIMAL32'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT256: 'UINT256'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECFLOAT: 'DECFLOAT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDECIMAL: 'UDECIMAL'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UTINYINT: 'UTINYINT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGINT: 'BIGINT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT128: 'INT128'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UMEDIUMINT: 'UMEDIUMINT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL: 'DECIMAL'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MONEY: 'MONEY'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDOUBLE: 'UDOUBLE'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TINYINT: 'TINYINT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UBIGINT: 'UBIGINT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT: 'INT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLINT: 'SMALLINT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL256: 'DECIMAL256'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL128: 'DECIMAL128'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIT: 'BIT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DOUBLE: 'DOUBLE'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT: 'UINT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT256: 'INT256'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLMONEY: 'SMALLMONEY'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.USMALLINT: 'USMALLINT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MEDIUMINT: 'MEDIUMINT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT128: 'UINT128'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL64: 'DECIMAL64'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.FLOAT: 'FLOAT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL32: 'DECIMAL32'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT256: 'UINT256'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECFLOAT: 'DECFLOAT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DATE: 'DATE'>, <DType.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<lambda>>, (<DType.INTERVAL: 'INTERVAL'>, <DType.DATE: 'DATE'>): <function TypeAnnotator.<lambda>>}
schema
dialect
expression_metadata
coerces_to
binary_coercions
def clear(self) -> None:
230    def clear(self) -> None:
231        self._visited.clear()
232        self._null_expressions.clear()
233        self._setop_column_types.clear()
234        self._scope_selects.clear()
def annotate(self, expression: ~E, annotate_scope: bool = True) -> ~E:
261    def annotate(self, expression: E, annotate_scope: bool = True) -> E:
262        # This flag is used to avoid costly scope traversals when we only care about annotating
263        # non-column expressions (partial type inference), e.g., when simplifying in the optimizer
264        if annotate_scope:
265            for scope in traverse_scope(expression):
266                self.annotate_scope(scope)
267
268        # This takes care of non-traversable expressions
269        self._annotate_expression(expression)
270
271        # Replace NULL type with the default type of the targeted dialect, since the former is not an actual type;
272        # it is mostly used to aid type coercion, e.g. in query set operations.
273        # TODO (mypyc): uses list() + _set_type instead of direct expr.type = ... because
274        # mypyc's property setter bypass rejects DType, and _set_type modifies the dict.
275        for expr in list(self._null_expressions.values()):
276            self._set_type(expr, self.dialect.DEFAULT_NULL_TYPE)
277
278        return expression
def annotate_scope(self, scope: sqlglot.optimizer.scope.Scope) -> None:
329    def annotate_scope(self, scope: Scope) -> None:
330        if isinstance(self.schema, MappingSchema):
331            for table_column in scope.table_columns:
332                source = scope.sources.get(table_column.name)
333
334                if isinstance(source, exp.Table):
335                    schema = self.schema.find(
336                        source, raise_on_missing=False, ensure_data_types=True
337                    )
338                    if not isinstance(schema, dict):
339                        continue
340
341                    struct_type = exp.DataType(
342                        this=exp.DType.STRUCT,
343                        expressions=[
344                            exp.ColumnDef(this=exp.to_identifier(str(c)), kind=kind)
345                            for c, kind in schema.items()
346                        ],
347                        nested=True,
348                    )
349                    self._set_type(table_column, struct_type)
350                elif (
351                    isinstance(source, Scope)
352                    and isinstance(source.expression, exp.Query)
353                    and (
354                        source.expression.meta.get("query_type") or exp.DType.UNKNOWN.into_expr()
355                    ).is_type(exp.DType.STRUCT)
356                ):
357                    self._set_type(table_column, source.expression.meta["query_type"])
358
359        # Iterate through all the expressions of the current scope in post-order, and annotate
360        self._annotate_expression(scope.expression, scope)
361        self._fixup_order_by_aliases(scope)
362
363        if self.dialect.QUERY_RESULTS_ARE_STRUCTS and isinstance(scope.expression, exp.Query):
364            struct_type = exp.DataType(
365                this=exp.DType.STRUCT,
366                expressions=[
367                    exp.ColumnDef(
368                        this=exp.to_identifier(select.output_name),
369                        kind=select.type.copy() if select.type else None,
370                    )
371                    for select in scope.expression.selects
372                ],
373                nested=True,
374            )
375
376            if not any(
377                cd.kind.is_type(exp.DType.UNKNOWN) for cd in struct_type.expressions if cd.kind
378            ):
379                # We don't use `_set_type` on purpose here. If we annotated the query directly, then
380                # using it in other contexts (e.g., ARRAY(<query>)) could result in incorrect type
381                # annotations, i.e., it shouldn't be interpreted as a STRUCT value.
382                scope.expression.meta["query_type"] = struct_type