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