Edit on GitHub

sqlglot.optimizer.annotate_types

  1from __future__ import annotations
  2
  3import functools
  4import typing as t
  5
  6from sqlglot import exp
  7from sqlglot.helper import (
  8    ensure_list,
  9    is_date_unit,
 10    is_iso_date,
 11    is_iso_datetime,
 12    seq_get,
 13)
 14from sqlglot.optimizer.scope import Scope, traverse_scope
 15from sqlglot.schema import MappingSchema, Schema, ensure_schema
 16from sqlglot.dialects.dialect import Dialect
 17
 18if t.TYPE_CHECKING:
 19    from sqlglot._typing import B, E
 20
 21    BinaryCoercionFunc = t.Callable[[exp.Expression, exp.Expression], exp.DataType.Type]
 22    BinaryCoercions = t.Dict[
 23        t.Tuple[exp.DataType.Type, exp.DataType.Type],
 24        BinaryCoercionFunc,
 25    ]
 26
 27    from sqlglot.dialects.dialect import DialectType, AnnotatorsType
 28
 29
 30def annotate_types(
 31    expression: E,
 32    schema: t.Optional[t.Dict | Schema] = None,
 33    annotators: t.Optional[AnnotatorsType] = None,
 34    coerces_to: t.Optional[t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]]] = None,
 35    dialect: DialectType = None,
 36) -> E:
 37    """
 38    Infers the types of an expression, annotating its AST accordingly.
 39
 40    Example:
 41        >>> import sqlglot
 42        >>> schema = {"y": {"cola": "SMALLINT"}}
 43        >>> sql = "SELECT x.cola + 2.5 AS cola FROM (SELECT y.cola AS cola FROM y AS y) AS x"
 44        >>> annotated_expr = annotate_types(sqlglot.parse_one(sql), schema=schema)
 45        >>> annotated_expr.expressions[0].type.this  # Get the type of "x.cola + 2.5 AS cola"
 46        <Type.DOUBLE: 'DOUBLE'>
 47
 48    Args:
 49        expression: Expression to annotate.
 50        schema: Database schema.
 51        annotators: Maps expression type to corresponding annotation function.
 52        coerces_to: Maps expression type to set of types that it can be coerced into.
 53
 54    Returns:
 55        The expression annotated with types.
 56    """
 57
 58    schema = ensure_schema(schema, dialect=dialect)
 59
 60    return TypeAnnotator(schema, annotators, coerces_to).annotate(expression)
 61
 62
 63def _coerce_date_literal(l: exp.Expression, unit: t.Optional[exp.Expression]) -> exp.DataType.Type:
 64    date_text = l.name
 65    is_iso_date_ = is_iso_date(date_text)
 66
 67    if is_iso_date_ and is_date_unit(unit):
 68        return exp.DataType.Type.DATE
 69
 70    # An ISO date is also an ISO datetime, but not vice versa
 71    if is_iso_date_ or is_iso_datetime(date_text):
 72        return exp.DataType.Type.DATETIME
 73
 74    return exp.DataType.Type.UNKNOWN
 75
 76
 77def _coerce_date(l: exp.Expression, unit: t.Optional[exp.Expression]) -> exp.DataType.Type:
 78    if not is_date_unit(unit):
 79        return exp.DataType.Type.DATETIME
 80    return l.type.this if l.type else exp.DataType.Type.UNKNOWN
 81
 82
 83def swap_args(func: BinaryCoercionFunc) -> BinaryCoercionFunc:
 84    @functools.wraps(func)
 85    def _swapped(l: exp.Expression, r: exp.Expression) -> exp.DataType.Type:
 86        return func(r, l)
 87
 88    return _swapped
 89
 90
 91def swap_all(coercions: BinaryCoercions) -> BinaryCoercions:
 92    return {**coercions, **{(b, a): swap_args(func) for (a, b), func in coercions.items()}}
 93
 94
 95class _TypeAnnotator(type):
 96    def __new__(cls, clsname, bases, attrs):
 97        klass = super().__new__(cls, clsname, bases, attrs)
 98
 99        # Highest-to-lowest type precedence, as specified in Spark's docs (ANSI):
100        # https://spark.apache.org/docs/3.2.0/sql-ref-ansi-compliance.html
101        text_precedence = (
102            exp.DataType.Type.TEXT,
103            exp.DataType.Type.NVARCHAR,
104            exp.DataType.Type.VARCHAR,
105            exp.DataType.Type.NCHAR,
106            exp.DataType.Type.CHAR,
107        )
108        numeric_precedence = (
109            exp.DataType.Type.DOUBLE,
110            exp.DataType.Type.FLOAT,
111            exp.DataType.Type.DECIMAL,
112            exp.DataType.Type.BIGINT,
113            exp.DataType.Type.INT,
114            exp.DataType.Type.SMALLINT,
115            exp.DataType.Type.TINYINT,
116        )
117        timelike_precedence = (
118            exp.DataType.Type.TIMESTAMPLTZ,
119            exp.DataType.Type.TIMESTAMPTZ,
120            exp.DataType.Type.TIMESTAMP,
121            exp.DataType.Type.DATETIME,
122            exp.DataType.Type.DATE,
123        )
124
125        for type_precedence in (text_precedence, numeric_precedence, timelike_precedence):
126            coerces_to = set()
127            for data_type in type_precedence:
128                klass.COERCES_TO[data_type] = coerces_to.copy()
129                coerces_to |= {data_type}
130
131        # NULL can be coerced to any type, so e.g. NULL + 1 will have type INT
132        klass.COERCES_TO[exp.DataType.Type.NULL] = {
133            *text_precedence,
134            *numeric_precedence,
135            *timelike_precedence,
136        }
137
138        return klass
139
140
141class TypeAnnotator(metaclass=_TypeAnnotator):
142    NESTED_TYPES = {
143        exp.DataType.Type.ARRAY,
144    }
145
146    # Specifies what types a given type can be coerced into (autofilled)
147    COERCES_TO: t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]] = {}
148
149    # Coercion functions for binary operations.
150    # Map of type pairs to a callable that takes both sides of the binary operation and returns the resulting type.
151    BINARY_COERCIONS: BinaryCoercions = {
152        **swap_all(
153            {
154                (t, exp.DataType.Type.INTERVAL): lambda l, r: _coerce_date_literal(
155                    l, r.args.get("unit")
156                )
157                for t in exp.DataType.TEXT_TYPES
158            }
159        ),
160        **swap_all(
161            {
162                # text + numeric will yield the numeric type to match most dialects' semantics
163                (text, numeric): lambda l, r: t.cast(
164                    exp.DataType.Type, l.type if l.type in exp.DataType.NUMERIC_TYPES else r.type
165                )
166                for text in exp.DataType.TEXT_TYPES
167                for numeric in exp.DataType.NUMERIC_TYPES
168            }
169        ),
170        **swap_all(
171            {
172                (exp.DataType.Type.DATE, exp.DataType.Type.INTERVAL): lambda l, r: _coerce_date(
173                    l, r.args.get("unit")
174                ),
175            }
176        ),
177    }
178
179    def __init__(
180        self,
181        schema: Schema,
182        annotators: t.Optional[AnnotatorsType] = None,
183        coerces_to: t.Optional[t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]]] = None,
184        binary_coercions: t.Optional[BinaryCoercions] = None,
185    ) -> None:
186        self.schema = schema
187        self.annotators = annotators or Dialect.get_or_raise(schema.dialect).ANNOTATORS
188        self.coerces_to = (
189            coerces_to or Dialect.get_or_raise(schema.dialect).COERCES_TO or self.COERCES_TO
190        )
191        self.binary_coercions = binary_coercions or self.BINARY_COERCIONS
192
193        # Caches the ids of annotated sub-Expressions, to ensure we only visit them once
194        self._visited: t.Set[int] = set()
195
196        # Maps an exp.SetOperation's id (e.g. UNION) to its projection types. This is computed if the
197        # exp.SetOperation is the expression of a scope source, as selecting from it multiple times
198        # would reprocess the entire subtree to coerce the types of its operands' projections
199        self._setop_column_types: t.Dict[int, t.Dict[str, exp.DataType | exp.DataType.Type]] = {}
200
201    def _set_type(
202        self, expression: exp.Expression, target_type: t.Optional[exp.DataType | exp.DataType.Type]
203    ) -> None:
204        expression.type = target_type or exp.DataType.Type.UNKNOWN  # type: ignore
205        self._visited.add(id(expression))
206
207    def annotate(self, expression: E) -> E:
208        for scope in traverse_scope(expression):
209            self.annotate_scope(scope)
210        return self._maybe_annotate(expression)  # This takes care of non-traversable expressions
211
212    def annotate_scope(self, scope: Scope) -> None:
213        selects = {}
214        for name, source in scope.sources.items():
215            if not isinstance(source, Scope):
216                continue
217
218            expression = source.expression
219            if isinstance(expression, exp.UDTF):
220                values = []
221
222                if isinstance(expression, exp.Lateral):
223                    if isinstance(expression.this, exp.Explode):
224                        values = [expression.this.this]
225                elif isinstance(expression, exp.Unnest):
226                    values = [expression]
227                elif not isinstance(expression, exp.TableFromRows):
228                    values = expression.expressions[0].expressions
229
230                if not values:
231                    continue
232
233                selects[name] = {
234                    alias: column.type
235                    for alias, column in zip(expression.alias_column_names, values)
236                }
237            elif isinstance(expression, exp.SetOperation) and len(expression.left.selects) == len(
238                expression.right.selects
239            ):
240                selects[name] = col_types = self._setop_column_types.setdefault(id(expression), {})
241
242                if not col_types:
243                    # Process a chain / sub-tree of set operations
244                    for set_op in expression.walk(
245                        prune=lambda n: not isinstance(n, (exp.SetOperation, exp.Subquery))
246                    ):
247                        if not isinstance(set_op, exp.SetOperation):
248                            continue
249
250                        if set_op.args.get("by_name"):
251                            r_type_by_select = {
252                                s.alias_or_name: s.type for s in set_op.right.selects
253                            }
254                            setop_cols = {
255                                s.alias_or_name: self._maybe_coerce(
256                                    t.cast(exp.DataType, s.type),
257                                    r_type_by_select.get(s.alias_or_name)
258                                    or exp.DataType.Type.UNKNOWN,
259                                )
260                                for s in set_op.left.selects
261                            }
262                        else:
263                            setop_cols = {
264                                ls.alias_or_name: self._maybe_coerce(
265                                    t.cast(exp.DataType, ls.type), t.cast(exp.DataType, rs.type)
266                                )
267                                for ls, rs in zip(set_op.left.selects, set_op.right.selects)
268                            }
269
270                        # Coerce intermediate results with the previously registered types, if they exist
271                        for col_name, col_type in setop_cols.items():
272                            col_types[col_name] = self._maybe_coerce(
273                                col_type, col_types.get(col_name, exp.DataType.Type.NULL)
274                            )
275
276            else:
277                selects[name] = {s.alias_or_name: s.type for s in expression.selects}
278
279        # First annotate the current scope's column references
280        for col in scope.columns:
281            if not col.table:
282                continue
283
284            source = scope.sources.get(col.table)
285            if isinstance(source, exp.Table):
286                self._set_type(col, self.schema.get_column_type(source, col))
287            elif source:
288                if col.table in selects and col.name in selects[col.table]:
289                    self._set_type(col, selects[col.table][col.name])
290                elif isinstance(source.expression, exp.Unnest):
291                    self._set_type(col, source.expression.type)
292
293        if isinstance(self.schema, MappingSchema):
294            for table_column in scope.table_columns:
295                source = scope.sources.get(table_column.name)
296
297                if isinstance(source, exp.Table):
298                    schema = self.schema.find(
299                        source, raise_on_missing=False, ensure_data_types=True
300                    )
301                    if not isinstance(schema, dict):
302                        continue
303
304                    struct_type = exp.DataType(
305                        this=exp.DataType.Type.STRUCT,
306                        expressions=[
307                            exp.ColumnDef(this=exp.to_identifier(c), kind=kind)
308                            for c, kind in schema.items()
309                        ],
310                        nested=True,
311                    )
312                    self._set_type(table_column, struct_type)
313                elif (
314                    isinstance(source, Scope)
315                    and isinstance(source.expression, exp.Query)
316                    and (
317                        source.expression.meta.get("query_type") or exp.DataType.build("UNKNOWN")
318                    ).is_type(exp.DataType.Type.STRUCT)
319                ):
320                    self._set_type(table_column, source.expression.meta["query_type"])
321
322        # Then (possibly) annotate the remaining expressions in the scope
323        self._maybe_annotate(scope.expression)
324
325        if self.schema.dialect == "bigquery" and isinstance(scope.expression, exp.Query):
326            struct_type = exp.DataType(
327                this=exp.DataType.Type.STRUCT,
328                expressions=[
329                    exp.ColumnDef(
330                        this=exp.to_identifier(select.output_name),
331                        kind=select.type.copy() if select.type else None,
332                    )
333                    for select in scope.expression.selects
334                ],
335                nested=True,
336            )
337
338            if not any(
339                cd.kind.is_type(exp.DataType.Type.UNKNOWN)
340                for cd in struct_type.expressions
341                if cd.kind
342            ):
343                # We don't use `_set_type` on purpose here. If we annotated the query directly, then
344                # using it in other contexts (e.g., ARRAY(<query>)) could result in incorrect type
345                # annotations, i.e., it shouldn't be interpreted as a STRUCT value.
346                scope.expression.meta["query_type"] = struct_type
347
348    def _maybe_annotate(self, expression: E) -> E:
349        if id(expression) in self._visited:
350            return expression  # We've already inferred the expression's type
351
352        annotator = self.annotators.get(expression.__class__)
353
354        return (
355            annotator(self, expression)
356            if annotator
357            else self._annotate_with_type(expression, exp.DataType.Type.UNKNOWN)
358        )
359
360    def _annotate_args(self, expression: E) -> E:
361        for value in expression.iter_expressions():
362            self._maybe_annotate(value)
363
364        return expression
365
366    def _maybe_coerce(
367        self,
368        type1: exp.DataType | exp.DataType.Type,
369        type2: exp.DataType | exp.DataType.Type,
370    ) -> exp.DataType | exp.DataType.Type:
371        """
372        Returns type2 if type1 can be coerced into it, otherwise type1.
373
374        If either type is parameterized (e.g. DECIMAL(18, 2) contains two parameters),
375        we assume type1 does not coerce into type2, so we also return it in this case.
376        """
377        if isinstance(type1, exp.DataType):
378            if type1.expressions:
379                return type1
380            type1_value = type1.this
381        else:
382            type1_value = type1
383
384        if isinstance(type2, exp.DataType):
385            if type2.expressions:
386                return type2
387            type2_value = type2.this
388        else:
389            type2_value = type2
390
391        # We propagate the UNKNOWN type upwards if found
392        if exp.DataType.Type.UNKNOWN in (type1_value, type2_value):
393            return exp.DataType.Type.UNKNOWN
394
395        return type2_value if type2_value in self.coerces_to.get(type1_value, {}) else type1_value
396
397    def _annotate_binary(self, expression: B) -> B:
398        self._annotate_args(expression)
399
400        left, right = expression.left, expression.right
401        left_type, right_type = left.type.this, right.type.this  # type: ignore
402
403        if isinstance(expression, (exp.Connector, exp.Predicate)):
404            self._set_type(expression, exp.DataType.Type.BOOLEAN)
405        elif (left_type, right_type) in self.binary_coercions:
406            self._set_type(expression, self.binary_coercions[(left_type, right_type)](left, right))
407        else:
408            self._set_type(expression, self._maybe_coerce(left_type, right_type))
409
410        return expression
411
412    def _annotate_unary(self, expression: E) -> E:
413        self._annotate_args(expression)
414
415        if isinstance(expression, exp.Not):
416            self._set_type(expression, exp.DataType.Type.BOOLEAN)
417        else:
418            self._set_type(expression, expression.this.type)
419
420        return expression
421
422    def _annotate_literal(self, expression: exp.Literal) -> exp.Literal:
423        if expression.is_string:
424            self._set_type(expression, exp.DataType.Type.VARCHAR)
425        elif expression.is_int:
426            self._set_type(expression, exp.DataType.Type.INT)
427        else:
428            self._set_type(expression, exp.DataType.Type.DOUBLE)
429
430        return expression
431
432    def _annotate_with_type(
433        self, expression: E, target_type: exp.DataType | exp.DataType.Type
434    ) -> E:
435        self._set_type(expression, target_type)
436        return self._annotate_args(expression)
437
438    @t.no_type_check
439    def _annotate_by_args(
440        self,
441        expression: E,
442        *args: str,
443        promote: bool = False,
444        array: bool = False,
445    ) -> E:
446        self._annotate_args(expression)
447
448        expressions: t.List[exp.Expression] = []
449        for arg in args:
450            arg_expr = expression.args.get(arg)
451            expressions.extend(expr for expr in ensure_list(arg_expr) if expr)
452
453        last_datatype = None
454        for expr in expressions:
455            expr_type = expr.type
456
457            # Stop at the first nested data type found - we don't want to _maybe_coerce nested types
458            if expr_type.args.get("nested"):
459                last_datatype = expr_type
460                break
461
462            if not expr_type.is_type(exp.DataType.Type.UNKNOWN):
463                last_datatype = self._maybe_coerce(last_datatype or expr_type, expr_type)
464
465        self._set_type(expression, last_datatype or exp.DataType.Type.UNKNOWN)
466
467        if promote:
468            if expression.type.this in exp.DataType.INTEGER_TYPES:
469                self._set_type(expression, exp.DataType.Type.BIGINT)
470            elif expression.type.this in exp.DataType.FLOAT_TYPES:
471                self._set_type(expression, exp.DataType.Type.DOUBLE)
472
473        if array:
474            self._set_type(
475                expression,
476                exp.DataType(
477                    this=exp.DataType.Type.ARRAY, expressions=[expression.type], nested=True
478                ),
479            )
480
481        return expression
482
483    def _annotate_timeunit(
484        self, expression: exp.TimeUnit | exp.DateTrunc
485    ) -> exp.TimeUnit | exp.DateTrunc:
486        self._annotate_args(expression)
487
488        if expression.this.type.this in exp.DataType.TEXT_TYPES:
489            datatype = _coerce_date_literal(expression.this, expression.unit)
490        elif expression.this.type.this in exp.DataType.TEMPORAL_TYPES:
491            datatype = _coerce_date(expression.this, expression.unit)
492        else:
493            datatype = exp.DataType.Type.UNKNOWN
494
495        self._set_type(expression, datatype)
496        return expression
497
498    def _annotate_bracket(self, expression: exp.Bracket) -> exp.Bracket:
499        self._annotate_args(expression)
500
501        bracket_arg = expression.expressions[0]
502        this = expression.this
503
504        if isinstance(bracket_arg, exp.Slice):
505            self._set_type(expression, this.type)
506        elif this.type.is_type(exp.DataType.Type.ARRAY):
507            self._set_type(expression, seq_get(this.type.expressions, 0))
508        elif isinstance(this, (exp.Map, exp.VarMap)) and bracket_arg in this.keys:
509            index = this.keys.index(bracket_arg)
510            value = seq_get(this.values, index)
511            self._set_type(expression, value.type if value else None)
512        else:
513            self._set_type(expression, exp.DataType.Type.UNKNOWN)
514
515        return expression
516
517    def _annotate_div(self, expression: exp.Div) -> exp.Div:
518        self._annotate_args(expression)
519
520        left_type, right_type = expression.left.type.this, expression.right.type.this  # type: ignore
521
522        if (
523            expression.args.get("typed")
524            and left_type in exp.DataType.INTEGER_TYPES
525            and right_type in exp.DataType.INTEGER_TYPES
526        ):
527            self._set_type(expression, exp.DataType.Type.BIGINT)
528        else:
529            self._set_type(expression, self._maybe_coerce(left_type, right_type))
530            if expression.type and expression.type.this not in exp.DataType.REAL_TYPES:
531                self._set_type(
532                    expression, self._maybe_coerce(expression.type, exp.DataType.Type.DOUBLE)
533                )
534
535        return expression
536
537    def _annotate_dot(self, expression: exp.Dot) -> exp.Dot:
538        self._annotate_args(expression)
539        self._set_type(expression, None)
540        this_type = expression.this.type
541
542        if this_type and this_type.is_type(exp.DataType.Type.STRUCT):
543            for e in this_type.expressions:
544                if e.name == expression.expression.name:
545                    self._set_type(expression, e.kind)
546                    break
547
548        return expression
549
550    def _annotate_explode(self, expression: exp.Explode) -> exp.Explode:
551        self._annotate_args(expression)
552        self._set_type(expression, seq_get(expression.this.type.expressions, 0))
553        return expression
554
555    def _annotate_unnest(self, expression: exp.Unnest) -> exp.Unnest:
556        self._annotate_args(expression)
557        child = seq_get(expression.expressions, 0)
558
559        if child and child.is_type(exp.DataType.Type.ARRAY):
560            expr_type = seq_get(child.type.expressions, 0)
561        else:
562            expr_type = None
563
564        self._set_type(expression, expr_type)
565        return expression
566
567    def _annotate_struct_value(
568        self, expression: exp.Expression
569    ) -> t.Optional[exp.DataType] | exp.ColumnDef:
570        alias = expression.args.get("alias")
571        if alias:
572            return exp.ColumnDef(this=alias.copy(), kind=expression.type)
573
574        # Case: key = value or key := value
575        if expression.expression:
576            return exp.ColumnDef(this=expression.this.copy(), kind=expression.expression.type)
577
578        return expression.type
579
580    def _annotate_struct(self, expression: exp.Struct) -> exp.Struct:
581        self._annotate_args(expression)
582        self._set_type(
583            expression,
584            exp.DataType(
585                this=exp.DataType.Type.STRUCT,
586                expressions=[self._annotate_struct_value(expr) for expr in expression.expressions],
587                nested=True,
588            ),
589        )
590        return expression
591
592    @t.overload
593    def _annotate_map(self, expression: exp.Map) -> exp.Map: ...
594
595    @t.overload
596    def _annotate_map(self, expression: exp.VarMap) -> exp.VarMap: ...
597
598    def _annotate_map(self, expression):
599        self._annotate_args(expression)
600
601        keys = expression.args.get("keys")
602        values = expression.args.get("values")
603
604        map_type = exp.DataType(this=exp.DataType.Type.MAP)
605        if isinstance(keys, exp.Array) and isinstance(values, exp.Array):
606            key_type = seq_get(keys.type.expressions, 0) or exp.DataType.Type.UNKNOWN
607            value_type = seq_get(values.type.expressions, 0) or exp.DataType.Type.UNKNOWN
608
609            if key_type != exp.DataType.Type.UNKNOWN and value_type != exp.DataType.Type.UNKNOWN:
610                map_type.set("expressions", [key_type, value_type])
611                map_type.set("nested", True)
612
613        self._set_type(expression, map_type)
614        return expression
615
616    def _annotate_to_map(self, expression: exp.ToMap) -> exp.ToMap:
617        self._annotate_args(expression)
618
619        map_type = exp.DataType(this=exp.DataType.Type.MAP)
620        arg = expression.this
621        if arg.is_type(exp.DataType.Type.STRUCT):
622            for coldef in arg.type.expressions:
623                kind = coldef.kind
624                if kind != exp.DataType.Type.UNKNOWN:
625                    map_type.set("expressions", [exp.DataType.build("varchar"), kind])
626                    map_type.set("nested", True)
627                    break
628
629        self._set_type(expression, map_type)
630        return expression
631
632    def _annotate_extract(self, expression: exp.Extract) -> exp.Extract:
633        self._annotate_args(expression)
634        part = expression.name
635        if part == "TIME":
636            self._set_type(expression, exp.DataType.Type.TIME)
637        elif part == "DATE":
638            self._set_type(expression, exp.DataType.Type.DATE)
639        else:
640            self._set_type(expression, exp.DataType.Type.INT)
641        return expression
642
643    def _annotate_by_array_element(self, expression: exp.Expression) -> exp.Expression:
644        self._annotate_args(expression)
645
646        array_arg = expression.this
647        if array_arg.type.is_type(exp.DataType.Type.ARRAY):
648            element_type = seq_get(array_arg.type.expressions, 0) or exp.DataType.Type.UNKNOWN
649            self._set_type(expression, element_type)
650        else:
651            self._set_type(expression, exp.DataType.Type.UNKNOWN)
652
653        return expression
def annotate_types( expression: ~E, schema: Union[Dict, sqlglot.schema.Schema, NoneType] = None, annotators: Optional[Dict[Type[~E], Callable[[TypeAnnotator, ~E], ~E]]] = 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) -> ~E:
31def annotate_types(
32    expression: E,
33    schema: t.Optional[t.Dict | Schema] = None,
34    annotators: t.Optional[AnnotatorsType] = None,
35    coerces_to: t.Optional[t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]]] = None,
36    dialect: DialectType = None,
37) -> E:
38    """
39    Infers the types of an expression, annotating its AST accordingly.
40
41    Example:
42        >>> import sqlglot
43        >>> schema = {"y": {"cola": "SMALLINT"}}
44        >>> sql = "SELECT x.cola + 2.5 AS cola FROM (SELECT y.cola AS cola FROM y AS y) AS x"
45        >>> annotated_expr = annotate_types(sqlglot.parse_one(sql), schema=schema)
46        >>> annotated_expr.expressions[0].type.this  # Get the type of "x.cola + 2.5 AS cola"
47        <Type.DOUBLE: 'DOUBLE'>
48
49    Args:
50        expression: Expression to annotate.
51        schema: Database schema.
52        annotators: Maps expression type to corresponding annotation function.
53        coerces_to: Maps expression type to set of types that it can be coerced into.
54
55    Returns:
56        The expression annotated with types.
57    """
58
59    schema = ensure_schema(schema, dialect=dialect)
60
61    return TypeAnnotator(schema, annotators, coerces_to).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.
  • annotators: Maps expression type to corresponding annotation function.
  • coerces_to: Maps expression type to set of types that it can be coerced into.
Returns:

The expression annotated with types.

84def swap_args(func: BinaryCoercionFunc) -> BinaryCoercionFunc:
85    @functools.wraps(func)
86    def _swapped(l: exp.Expression, r: exp.Expression) -> exp.DataType.Type:
87        return func(r, l)
88
89    return _swapped
92def swap_all(coercions: BinaryCoercions) -> BinaryCoercions:
93    return {**coercions, **{(b, a): swap_args(func) for (a, b), func in coercions.items()}}
class TypeAnnotator:
142class TypeAnnotator(metaclass=_TypeAnnotator):
143    NESTED_TYPES = {
144        exp.DataType.Type.ARRAY,
145    }
146
147    # Specifies what types a given type can be coerced into (autofilled)
148    COERCES_TO: t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]] = {}
149
150    # Coercion functions for binary operations.
151    # Map of type pairs to a callable that takes both sides of the binary operation and returns the resulting type.
152    BINARY_COERCIONS: BinaryCoercions = {
153        **swap_all(
154            {
155                (t, exp.DataType.Type.INTERVAL): lambda l, r: _coerce_date_literal(
156                    l, r.args.get("unit")
157                )
158                for t in exp.DataType.TEXT_TYPES
159            }
160        ),
161        **swap_all(
162            {
163                # text + numeric will yield the numeric type to match most dialects' semantics
164                (text, numeric): lambda l, r: t.cast(
165                    exp.DataType.Type, l.type if l.type in exp.DataType.NUMERIC_TYPES else r.type
166                )
167                for text in exp.DataType.TEXT_TYPES
168                for numeric in exp.DataType.NUMERIC_TYPES
169            }
170        ),
171        **swap_all(
172            {
173                (exp.DataType.Type.DATE, exp.DataType.Type.INTERVAL): lambda l, r: _coerce_date(
174                    l, r.args.get("unit")
175                ),
176            }
177        ),
178    }
179
180    def __init__(
181        self,
182        schema: Schema,
183        annotators: t.Optional[AnnotatorsType] = None,
184        coerces_to: t.Optional[t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]]] = None,
185        binary_coercions: t.Optional[BinaryCoercions] = None,
186    ) -> None:
187        self.schema = schema
188        self.annotators = annotators or Dialect.get_or_raise(schema.dialect).ANNOTATORS
189        self.coerces_to = (
190            coerces_to or Dialect.get_or_raise(schema.dialect).COERCES_TO or self.COERCES_TO
191        )
192        self.binary_coercions = binary_coercions or self.BINARY_COERCIONS
193
194        # Caches the ids of annotated sub-Expressions, to ensure we only visit them once
195        self._visited: t.Set[int] = set()
196
197        # Maps an exp.SetOperation's id (e.g. UNION) to its projection types. This is computed if the
198        # exp.SetOperation is the expression of a scope source, as selecting from it multiple times
199        # would reprocess the entire subtree to coerce the types of its operands' projections
200        self._setop_column_types: t.Dict[int, t.Dict[str, exp.DataType | exp.DataType.Type]] = {}
201
202    def _set_type(
203        self, expression: exp.Expression, target_type: t.Optional[exp.DataType | exp.DataType.Type]
204    ) -> None:
205        expression.type = target_type or exp.DataType.Type.UNKNOWN  # type: ignore
206        self._visited.add(id(expression))
207
208    def annotate(self, expression: E) -> E:
209        for scope in traverse_scope(expression):
210            self.annotate_scope(scope)
211        return self._maybe_annotate(expression)  # This takes care of non-traversable expressions
212
213    def annotate_scope(self, scope: Scope) -> None:
214        selects = {}
215        for name, source in scope.sources.items():
216            if not isinstance(source, Scope):
217                continue
218
219            expression = source.expression
220            if isinstance(expression, exp.UDTF):
221                values = []
222
223                if isinstance(expression, exp.Lateral):
224                    if isinstance(expression.this, exp.Explode):
225                        values = [expression.this.this]
226                elif isinstance(expression, exp.Unnest):
227                    values = [expression]
228                elif not isinstance(expression, exp.TableFromRows):
229                    values = expression.expressions[0].expressions
230
231                if not values:
232                    continue
233
234                selects[name] = {
235                    alias: column.type
236                    for alias, column in zip(expression.alias_column_names, values)
237                }
238            elif isinstance(expression, exp.SetOperation) and len(expression.left.selects) == len(
239                expression.right.selects
240            ):
241                selects[name] = col_types = self._setop_column_types.setdefault(id(expression), {})
242
243                if not col_types:
244                    # Process a chain / sub-tree of set operations
245                    for set_op in expression.walk(
246                        prune=lambda n: not isinstance(n, (exp.SetOperation, exp.Subquery))
247                    ):
248                        if not isinstance(set_op, exp.SetOperation):
249                            continue
250
251                        if set_op.args.get("by_name"):
252                            r_type_by_select = {
253                                s.alias_or_name: s.type for s in set_op.right.selects
254                            }
255                            setop_cols = {
256                                s.alias_or_name: self._maybe_coerce(
257                                    t.cast(exp.DataType, s.type),
258                                    r_type_by_select.get(s.alias_or_name)
259                                    or exp.DataType.Type.UNKNOWN,
260                                )
261                                for s in set_op.left.selects
262                            }
263                        else:
264                            setop_cols = {
265                                ls.alias_or_name: self._maybe_coerce(
266                                    t.cast(exp.DataType, ls.type), t.cast(exp.DataType, rs.type)
267                                )
268                                for ls, rs in zip(set_op.left.selects, set_op.right.selects)
269                            }
270
271                        # Coerce intermediate results with the previously registered types, if they exist
272                        for col_name, col_type in setop_cols.items():
273                            col_types[col_name] = self._maybe_coerce(
274                                col_type, col_types.get(col_name, exp.DataType.Type.NULL)
275                            )
276
277            else:
278                selects[name] = {s.alias_or_name: s.type for s in expression.selects}
279
280        # First annotate the current scope's column references
281        for col in scope.columns:
282            if not col.table:
283                continue
284
285            source = scope.sources.get(col.table)
286            if isinstance(source, exp.Table):
287                self._set_type(col, self.schema.get_column_type(source, col))
288            elif source:
289                if col.table in selects and col.name in selects[col.table]:
290                    self._set_type(col, selects[col.table][col.name])
291                elif isinstance(source.expression, exp.Unnest):
292                    self._set_type(col, source.expression.type)
293
294        if isinstance(self.schema, MappingSchema):
295            for table_column in scope.table_columns:
296                source = scope.sources.get(table_column.name)
297
298                if isinstance(source, exp.Table):
299                    schema = self.schema.find(
300                        source, raise_on_missing=False, ensure_data_types=True
301                    )
302                    if not isinstance(schema, dict):
303                        continue
304
305                    struct_type = exp.DataType(
306                        this=exp.DataType.Type.STRUCT,
307                        expressions=[
308                            exp.ColumnDef(this=exp.to_identifier(c), kind=kind)
309                            for c, kind in schema.items()
310                        ],
311                        nested=True,
312                    )
313                    self._set_type(table_column, struct_type)
314                elif (
315                    isinstance(source, Scope)
316                    and isinstance(source.expression, exp.Query)
317                    and (
318                        source.expression.meta.get("query_type") or exp.DataType.build("UNKNOWN")
319                    ).is_type(exp.DataType.Type.STRUCT)
320                ):
321                    self._set_type(table_column, source.expression.meta["query_type"])
322
323        # Then (possibly) annotate the remaining expressions in the scope
324        self._maybe_annotate(scope.expression)
325
326        if self.schema.dialect == "bigquery" and isinstance(scope.expression, exp.Query):
327            struct_type = exp.DataType(
328                this=exp.DataType.Type.STRUCT,
329                expressions=[
330                    exp.ColumnDef(
331                        this=exp.to_identifier(select.output_name),
332                        kind=select.type.copy() if select.type else None,
333                    )
334                    for select in scope.expression.selects
335                ],
336                nested=True,
337            )
338
339            if not any(
340                cd.kind.is_type(exp.DataType.Type.UNKNOWN)
341                for cd in struct_type.expressions
342                if cd.kind
343            ):
344                # We don't use `_set_type` on purpose here. If we annotated the query directly, then
345                # using it in other contexts (e.g., ARRAY(<query>)) could result in incorrect type
346                # annotations, i.e., it shouldn't be interpreted as a STRUCT value.
347                scope.expression.meta["query_type"] = struct_type
348
349    def _maybe_annotate(self, expression: E) -> E:
350        if id(expression) in self._visited:
351            return expression  # We've already inferred the expression's type
352
353        annotator = self.annotators.get(expression.__class__)
354
355        return (
356            annotator(self, expression)
357            if annotator
358            else self._annotate_with_type(expression, exp.DataType.Type.UNKNOWN)
359        )
360
361    def _annotate_args(self, expression: E) -> E:
362        for value in expression.iter_expressions():
363            self._maybe_annotate(value)
364
365        return expression
366
367    def _maybe_coerce(
368        self,
369        type1: exp.DataType | exp.DataType.Type,
370        type2: exp.DataType | exp.DataType.Type,
371    ) -> exp.DataType | exp.DataType.Type:
372        """
373        Returns type2 if type1 can be coerced into it, otherwise type1.
374
375        If either type is parameterized (e.g. DECIMAL(18, 2) contains two parameters),
376        we assume type1 does not coerce into type2, so we also return it in this case.
377        """
378        if isinstance(type1, exp.DataType):
379            if type1.expressions:
380                return type1
381            type1_value = type1.this
382        else:
383            type1_value = type1
384
385        if isinstance(type2, exp.DataType):
386            if type2.expressions:
387                return type2
388            type2_value = type2.this
389        else:
390            type2_value = type2
391
392        # We propagate the UNKNOWN type upwards if found
393        if exp.DataType.Type.UNKNOWN in (type1_value, type2_value):
394            return exp.DataType.Type.UNKNOWN
395
396        return type2_value if type2_value in self.coerces_to.get(type1_value, {}) else type1_value
397
398    def _annotate_binary(self, expression: B) -> B:
399        self._annotate_args(expression)
400
401        left, right = expression.left, expression.right
402        left_type, right_type = left.type.this, right.type.this  # type: ignore
403
404        if isinstance(expression, (exp.Connector, exp.Predicate)):
405            self._set_type(expression, exp.DataType.Type.BOOLEAN)
406        elif (left_type, right_type) in self.binary_coercions:
407            self._set_type(expression, self.binary_coercions[(left_type, right_type)](left, right))
408        else:
409            self._set_type(expression, self._maybe_coerce(left_type, right_type))
410
411        return expression
412
413    def _annotate_unary(self, expression: E) -> E:
414        self._annotate_args(expression)
415
416        if isinstance(expression, exp.Not):
417            self._set_type(expression, exp.DataType.Type.BOOLEAN)
418        else:
419            self._set_type(expression, expression.this.type)
420
421        return expression
422
423    def _annotate_literal(self, expression: exp.Literal) -> exp.Literal:
424        if expression.is_string:
425            self._set_type(expression, exp.DataType.Type.VARCHAR)
426        elif expression.is_int:
427            self._set_type(expression, exp.DataType.Type.INT)
428        else:
429            self._set_type(expression, exp.DataType.Type.DOUBLE)
430
431        return expression
432
433    def _annotate_with_type(
434        self, expression: E, target_type: exp.DataType | exp.DataType.Type
435    ) -> E:
436        self._set_type(expression, target_type)
437        return self._annotate_args(expression)
438
439    @t.no_type_check
440    def _annotate_by_args(
441        self,
442        expression: E,
443        *args: str,
444        promote: bool = False,
445        array: bool = False,
446    ) -> E:
447        self._annotate_args(expression)
448
449        expressions: t.List[exp.Expression] = []
450        for arg in args:
451            arg_expr = expression.args.get(arg)
452            expressions.extend(expr for expr in ensure_list(arg_expr) if expr)
453
454        last_datatype = None
455        for expr in expressions:
456            expr_type = expr.type
457
458            # Stop at the first nested data type found - we don't want to _maybe_coerce nested types
459            if expr_type.args.get("nested"):
460                last_datatype = expr_type
461                break
462
463            if not expr_type.is_type(exp.DataType.Type.UNKNOWN):
464                last_datatype = self._maybe_coerce(last_datatype or expr_type, expr_type)
465
466        self._set_type(expression, last_datatype or exp.DataType.Type.UNKNOWN)
467
468        if promote:
469            if expression.type.this in exp.DataType.INTEGER_TYPES:
470                self._set_type(expression, exp.DataType.Type.BIGINT)
471            elif expression.type.this in exp.DataType.FLOAT_TYPES:
472                self._set_type(expression, exp.DataType.Type.DOUBLE)
473
474        if array:
475            self._set_type(
476                expression,
477                exp.DataType(
478                    this=exp.DataType.Type.ARRAY, expressions=[expression.type], nested=True
479                ),
480            )
481
482        return expression
483
484    def _annotate_timeunit(
485        self, expression: exp.TimeUnit | exp.DateTrunc
486    ) -> exp.TimeUnit | exp.DateTrunc:
487        self._annotate_args(expression)
488
489        if expression.this.type.this in exp.DataType.TEXT_TYPES:
490            datatype = _coerce_date_literal(expression.this, expression.unit)
491        elif expression.this.type.this in exp.DataType.TEMPORAL_TYPES:
492            datatype = _coerce_date(expression.this, expression.unit)
493        else:
494            datatype = exp.DataType.Type.UNKNOWN
495
496        self._set_type(expression, datatype)
497        return expression
498
499    def _annotate_bracket(self, expression: exp.Bracket) -> exp.Bracket:
500        self._annotate_args(expression)
501
502        bracket_arg = expression.expressions[0]
503        this = expression.this
504
505        if isinstance(bracket_arg, exp.Slice):
506            self._set_type(expression, this.type)
507        elif this.type.is_type(exp.DataType.Type.ARRAY):
508            self._set_type(expression, seq_get(this.type.expressions, 0))
509        elif isinstance(this, (exp.Map, exp.VarMap)) and bracket_arg in this.keys:
510            index = this.keys.index(bracket_arg)
511            value = seq_get(this.values, index)
512            self._set_type(expression, value.type if value else None)
513        else:
514            self._set_type(expression, exp.DataType.Type.UNKNOWN)
515
516        return expression
517
518    def _annotate_div(self, expression: exp.Div) -> exp.Div:
519        self._annotate_args(expression)
520
521        left_type, right_type = expression.left.type.this, expression.right.type.this  # type: ignore
522
523        if (
524            expression.args.get("typed")
525            and left_type in exp.DataType.INTEGER_TYPES
526            and right_type in exp.DataType.INTEGER_TYPES
527        ):
528            self._set_type(expression, exp.DataType.Type.BIGINT)
529        else:
530            self._set_type(expression, self._maybe_coerce(left_type, right_type))
531            if expression.type and expression.type.this not in exp.DataType.REAL_TYPES:
532                self._set_type(
533                    expression, self._maybe_coerce(expression.type, exp.DataType.Type.DOUBLE)
534                )
535
536        return expression
537
538    def _annotate_dot(self, expression: exp.Dot) -> exp.Dot:
539        self._annotate_args(expression)
540        self._set_type(expression, None)
541        this_type = expression.this.type
542
543        if this_type and this_type.is_type(exp.DataType.Type.STRUCT):
544            for e in this_type.expressions:
545                if e.name == expression.expression.name:
546                    self._set_type(expression, e.kind)
547                    break
548
549        return expression
550
551    def _annotate_explode(self, expression: exp.Explode) -> exp.Explode:
552        self._annotate_args(expression)
553        self._set_type(expression, seq_get(expression.this.type.expressions, 0))
554        return expression
555
556    def _annotate_unnest(self, expression: exp.Unnest) -> exp.Unnest:
557        self._annotate_args(expression)
558        child = seq_get(expression.expressions, 0)
559
560        if child and child.is_type(exp.DataType.Type.ARRAY):
561            expr_type = seq_get(child.type.expressions, 0)
562        else:
563            expr_type = None
564
565        self._set_type(expression, expr_type)
566        return expression
567
568    def _annotate_struct_value(
569        self, expression: exp.Expression
570    ) -> t.Optional[exp.DataType] | exp.ColumnDef:
571        alias = expression.args.get("alias")
572        if alias:
573            return exp.ColumnDef(this=alias.copy(), kind=expression.type)
574
575        # Case: key = value or key := value
576        if expression.expression:
577            return exp.ColumnDef(this=expression.this.copy(), kind=expression.expression.type)
578
579        return expression.type
580
581    def _annotate_struct(self, expression: exp.Struct) -> exp.Struct:
582        self._annotate_args(expression)
583        self._set_type(
584            expression,
585            exp.DataType(
586                this=exp.DataType.Type.STRUCT,
587                expressions=[self._annotate_struct_value(expr) for expr in expression.expressions],
588                nested=True,
589            ),
590        )
591        return expression
592
593    @t.overload
594    def _annotate_map(self, expression: exp.Map) -> exp.Map: ...
595
596    @t.overload
597    def _annotate_map(self, expression: exp.VarMap) -> exp.VarMap: ...
598
599    def _annotate_map(self, expression):
600        self._annotate_args(expression)
601
602        keys = expression.args.get("keys")
603        values = expression.args.get("values")
604
605        map_type = exp.DataType(this=exp.DataType.Type.MAP)
606        if isinstance(keys, exp.Array) and isinstance(values, exp.Array):
607            key_type = seq_get(keys.type.expressions, 0) or exp.DataType.Type.UNKNOWN
608            value_type = seq_get(values.type.expressions, 0) or exp.DataType.Type.UNKNOWN
609
610            if key_type != exp.DataType.Type.UNKNOWN and value_type != exp.DataType.Type.UNKNOWN:
611                map_type.set("expressions", [key_type, value_type])
612                map_type.set("nested", True)
613
614        self._set_type(expression, map_type)
615        return expression
616
617    def _annotate_to_map(self, expression: exp.ToMap) -> exp.ToMap:
618        self._annotate_args(expression)
619
620        map_type = exp.DataType(this=exp.DataType.Type.MAP)
621        arg = expression.this
622        if arg.is_type(exp.DataType.Type.STRUCT):
623            for coldef in arg.type.expressions:
624                kind = coldef.kind
625                if kind != exp.DataType.Type.UNKNOWN:
626                    map_type.set("expressions", [exp.DataType.build("varchar"), kind])
627                    map_type.set("nested", True)
628                    break
629
630        self._set_type(expression, map_type)
631        return expression
632
633    def _annotate_extract(self, expression: exp.Extract) -> exp.Extract:
634        self._annotate_args(expression)
635        part = expression.name
636        if part == "TIME":
637            self._set_type(expression, exp.DataType.Type.TIME)
638        elif part == "DATE":
639            self._set_type(expression, exp.DataType.Type.DATE)
640        else:
641            self._set_type(expression, exp.DataType.Type.INT)
642        return expression
643
644    def _annotate_by_array_element(self, expression: exp.Expression) -> exp.Expression:
645        self._annotate_args(expression)
646
647        array_arg = expression.this
648        if array_arg.type.is_type(exp.DataType.Type.ARRAY):
649            element_type = seq_get(array_arg.type.expressions, 0) or exp.DataType.Type.UNKNOWN
650            self._set_type(expression, element_type)
651        else:
652            self._set_type(expression, exp.DataType.Type.UNKNOWN)
653
654        return expression
TypeAnnotator( schema: sqlglot.schema.Schema, annotators: Optional[Dict[Type[~E], Callable[[TypeAnnotator, ~E], ~E]]] = 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)
180    def __init__(
181        self,
182        schema: Schema,
183        annotators: t.Optional[AnnotatorsType] = None,
184        coerces_to: t.Optional[t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]]] = None,
185        binary_coercions: t.Optional[BinaryCoercions] = None,
186    ) -> None:
187        self.schema = schema
188        self.annotators = annotators or Dialect.get_or_raise(schema.dialect).ANNOTATORS
189        self.coerces_to = (
190            coerces_to or Dialect.get_or_raise(schema.dialect).COERCES_TO or self.COERCES_TO
191        )
192        self.binary_coercions = binary_coercions or self.BINARY_COERCIONS
193
194        # Caches the ids of annotated sub-Expressions, to ensure we only visit them once
195        self._visited: t.Set[int] = set()
196
197        # Maps an exp.SetOperation's id (e.g. UNION) to its projection types. This is computed if the
198        # exp.SetOperation is the expression of a scope source, as selecting from it multiple times
199        # would reprocess the entire subtree to coerce the types of its operands' projections
200        self._setop_column_types: t.Dict[int, t.Dict[str, exp.DataType | exp.DataType.Type]] = {}
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.TEXT: 'TEXT'>}, <Type.NCHAR: 'NCHAR'>: {<Type.NVARCHAR: 'NVARCHAR'>, <Type.VARCHAR: 'VARCHAR'>, <Type.TEXT: 'TEXT'>}, <Type.CHAR: 'CHAR'>: {<Type.NCHAR: 'NCHAR'>, <Type.NVARCHAR: 'NVARCHAR'>, <Type.VARCHAR: 'VARCHAR'>, <Type.TEXT: 'TEXT'>}, <Type.DOUBLE: 'DOUBLE'>: set(), <Type.FLOAT: 'FLOAT'>: {<Type.DOUBLE: 'DOUBLE'>}, <Type.DECIMAL: 'DECIMAL'>: {<Type.DOUBLE: 'DOUBLE'>, <Type.FLOAT: 'FLOAT'>}, <Type.BIGINT: 'BIGINT'>: {<Type.DOUBLE: 'DOUBLE'>, <Type.DECIMAL: 'DECIMAL'>, <Type.FLOAT: 'FLOAT'>}, <Type.INT: 'INT'>: {<Type.DOUBLE: 'DOUBLE'>, <Type.DECIMAL: 'DECIMAL'>, <Type.BIGINT: 'BIGINT'>, <Type.FLOAT: 'FLOAT'>}, <Type.SMALLINT: 'SMALLINT'>: {<Type.DOUBLE: 'DOUBLE'>, <Type.BIGINT: 'BIGINT'>, <Type.FLOAT: 'FLOAT'>, <Type.INT: 'INT'>, <Type.DECIMAL: 'DECIMAL'>}, <Type.TINYINT: 'TINYINT'>: {<Type.DOUBLE: 'DOUBLE'>, <Type.BIGINT: 'BIGINT'>, <Type.FLOAT: 'FLOAT'>, <Type.SMALLINT: 'SMALLINT'>, <Type.INT: 'INT'>, <Type.DECIMAL: 'DECIMAL'>}, <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.TIMESTAMP: 'TIMESTAMP'>, <Type.TIMESTAMPTZ: 'TIMESTAMPTZ'>}, <Type.DATE: 'DATE'>: {<Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <Type.TIMESTAMP: 'TIMESTAMP'>, <Type.DATETIME: 'DATETIME'>, <Type.TIMESTAMPTZ: 'TIMESTAMPTZ'>}, <Type.NULL: 'NULL'>: {<Type.BIGINT: 'BIGINT'>, <Type.TIMESTAMP: 'TIMESTAMP'>, <Type.NCHAR: 'NCHAR'>, <Type.CHAR: 'CHAR'>, <Type.TEXT: 'TEXT'>, <Type.DATETIME: 'DATETIME'>, <Type.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <Type.SMALLINT: 'SMALLINT'>, <Type.DECIMAL: 'DECIMAL'>, <Type.DOUBLE: 'DOUBLE'>, <Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <Type.NVARCHAR: 'NVARCHAR'>, <Type.TINYINT: 'TINYINT'>, <Type.FLOAT: 'FLOAT'>, <Type.DATE: 'DATE'>, <Type.INT: 'INT'>, <Type.VARCHAR: 'VARCHAR'>}}
BINARY_COERCIONS: Dict[Tuple[sqlglot.expressions.DataType.Type, sqlglot.expressions.DataType.Type], Callable[[sqlglot.expressions.Expression, sqlglot.expressions.Expression], sqlglot.expressions.DataType.Type]] = {(<Type.NCHAR: 'NCHAR'>, <Type.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INTERVAL: 'INTERVAL'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INTERVAL: 'INTERVAL'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INTERVAL: 'INTERVAL'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INTERVAL: 'INTERVAL'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INTERVAL: 'INTERVAL'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INTERVAL: 'INTERVAL'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.DOUBLE: 'DOUBLE'>): <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.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.DOUBLE: 'DOUBLE'>): <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.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.DOUBLE: 'DOUBLE'>): <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.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.DOUBLE: 'DOUBLE'>): <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.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.DOUBLE: 'DOUBLE'>): <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.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.DOUBLE: 'DOUBLE'>): <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.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MONEY: 'MONEY'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UMEDIUMINT: 'UMEDIUMINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT128: 'UINT128'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDOUBLE: 'UDOUBLE'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL: 'DECIMAL'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <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.DECIMAL128: 'DECIMAL128'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLMONEY: 'SMALLMONEY'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT: 'UINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL32: 'DECIMAL32'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL256: 'DECIMAL256'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MONEY: 'MONEY'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UMEDIUMINT: 'UMEDIUMINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT128: 'UINT128'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDOUBLE: 'UDOUBLE'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL: 'DECIMAL'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <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.DECIMAL128: 'DECIMAL128'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLMONEY: 'SMALLMONEY'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT: 'UINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL32: 'DECIMAL32'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL256: 'DECIMAL256'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MONEY: 'MONEY'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UMEDIUMINT: 'UMEDIUMINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT128: 'UINT128'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDOUBLE: 'UDOUBLE'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL: 'DECIMAL'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <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.DECIMAL128: 'DECIMAL128'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLMONEY: 'SMALLMONEY'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT: 'UINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL32: 'DECIMAL32'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL256: 'DECIMAL256'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MONEY: 'MONEY'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UMEDIUMINT: 'UMEDIUMINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT128: 'UINT128'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDOUBLE: 'UDOUBLE'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL: 'DECIMAL'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <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.DECIMAL128: 'DECIMAL128'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLMONEY: 'SMALLMONEY'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT: 'UINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL32: 'DECIMAL32'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL256: 'DECIMAL256'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MONEY: 'MONEY'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UMEDIUMINT: 'UMEDIUMINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT128: 'UINT128'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDOUBLE: 'UDOUBLE'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL: 'DECIMAL'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <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.DECIMAL128: 'DECIMAL128'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLMONEY: 'SMALLMONEY'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT: 'UINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL32: 'DECIMAL32'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL256: 'DECIMAL256'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MONEY: 'MONEY'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UMEDIUMINT: 'UMEDIUMINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT128: 'UINT128'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDOUBLE: 'UDOUBLE'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL: 'DECIMAL'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <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.DECIMAL128: 'DECIMAL128'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLMONEY: 'SMALLMONEY'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT: 'UINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL32: 'DECIMAL32'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL256: 'DECIMAL256'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DATE: 'DATE'>, <Type.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<lambda>>, (<Type.INTERVAL: 'INTERVAL'>, <Type.DATE: 'DATE'>): <function TypeAnnotator.<lambda>>}
schema
annotators
coerces_to
binary_coercions
def annotate(self, expression: ~E) -> ~E:
208    def annotate(self, expression: E) -> E:
209        for scope in traverse_scope(expression):
210            self.annotate_scope(scope)
211        return self._maybe_annotate(expression)  # This takes care of non-traversable expressions
def annotate_scope(self, scope: sqlglot.optimizer.scope.Scope) -> None:
213    def annotate_scope(self, scope: Scope) -> None:
214        selects = {}
215        for name, source in scope.sources.items():
216            if not isinstance(source, Scope):
217                continue
218
219            expression = source.expression
220            if isinstance(expression, exp.UDTF):
221                values = []
222
223                if isinstance(expression, exp.Lateral):
224                    if isinstance(expression.this, exp.Explode):
225                        values = [expression.this.this]
226                elif isinstance(expression, exp.Unnest):
227                    values = [expression]
228                elif not isinstance(expression, exp.TableFromRows):
229                    values = expression.expressions[0].expressions
230
231                if not values:
232                    continue
233
234                selects[name] = {
235                    alias: column.type
236                    for alias, column in zip(expression.alias_column_names, values)
237                }
238            elif isinstance(expression, exp.SetOperation) and len(expression.left.selects) == len(
239                expression.right.selects
240            ):
241                selects[name] = col_types = self._setop_column_types.setdefault(id(expression), {})
242
243                if not col_types:
244                    # Process a chain / sub-tree of set operations
245                    for set_op in expression.walk(
246                        prune=lambda n: not isinstance(n, (exp.SetOperation, exp.Subquery))
247                    ):
248                        if not isinstance(set_op, exp.SetOperation):
249                            continue
250
251                        if set_op.args.get("by_name"):
252                            r_type_by_select = {
253                                s.alias_or_name: s.type for s in set_op.right.selects
254                            }
255                            setop_cols = {
256                                s.alias_or_name: self._maybe_coerce(
257                                    t.cast(exp.DataType, s.type),
258                                    r_type_by_select.get(s.alias_or_name)
259                                    or exp.DataType.Type.UNKNOWN,
260                                )
261                                for s in set_op.left.selects
262                            }
263                        else:
264                            setop_cols = {
265                                ls.alias_or_name: self._maybe_coerce(
266                                    t.cast(exp.DataType, ls.type), t.cast(exp.DataType, rs.type)
267                                )
268                                for ls, rs in zip(set_op.left.selects, set_op.right.selects)
269                            }
270
271                        # Coerce intermediate results with the previously registered types, if they exist
272                        for col_name, col_type in setop_cols.items():
273                            col_types[col_name] = self._maybe_coerce(
274                                col_type, col_types.get(col_name, exp.DataType.Type.NULL)
275                            )
276
277            else:
278                selects[name] = {s.alias_or_name: s.type for s in expression.selects}
279
280        # First annotate the current scope's column references
281        for col in scope.columns:
282            if not col.table:
283                continue
284
285            source = scope.sources.get(col.table)
286            if isinstance(source, exp.Table):
287                self._set_type(col, self.schema.get_column_type(source, col))
288            elif source:
289                if col.table in selects and col.name in selects[col.table]:
290                    self._set_type(col, selects[col.table][col.name])
291                elif isinstance(source.expression, exp.Unnest):
292                    self._set_type(col, source.expression.type)
293
294        if isinstance(self.schema, MappingSchema):
295            for table_column in scope.table_columns:
296                source = scope.sources.get(table_column.name)
297
298                if isinstance(source, exp.Table):
299                    schema = self.schema.find(
300                        source, raise_on_missing=False, ensure_data_types=True
301                    )
302                    if not isinstance(schema, dict):
303                        continue
304
305                    struct_type = exp.DataType(
306                        this=exp.DataType.Type.STRUCT,
307                        expressions=[
308                            exp.ColumnDef(this=exp.to_identifier(c), kind=kind)
309                            for c, kind in schema.items()
310                        ],
311                        nested=True,
312                    )
313                    self._set_type(table_column, struct_type)
314                elif (
315                    isinstance(source, Scope)
316                    and isinstance(source.expression, exp.Query)
317                    and (
318                        source.expression.meta.get("query_type") or exp.DataType.build("UNKNOWN")
319                    ).is_type(exp.DataType.Type.STRUCT)
320                ):
321                    self._set_type(table_column, source.expression.meta["query_type"])
322
323        # Then (possibly) annotate the remaining expressions in the scope
324        self._maybe_annotate(scope.expression)
325
326        if self.schema.dialect == "bigquery" and isinstance(scope.expression, exp.Query):
327            struct_type = exp.DataType(
328                this=exp.DataType.Type.STRUCT,
329                expressions=[
330                    exp.ColumnDef(
331                        this=exp.to_identifier(select.output_name),
332                        kind=select.type.copy() if select.type else None,
333                    )
334                    for select in scope.expression.selects
335                ],
336                nested=True,
337            )
338
339            if not any(
340                cd.kind.is_type(exp.DataType.Type.UNKNOWN)
341                for cd in struct_type.expressions
342                if cd.kind
343            ):
344                # We don't use `_set_type` on purpose here. If we annotated the query directly, then
345                # using it in other contexts (e.g., ARRAY(<query>)) could result in incorrect type
346                # annotations, i.e., it shouldn't be interpreted as a STRUCT value.
347                scope.expression.meta["query_type"] = struct_type