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

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