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(this=exp.to_identifier(select.output_name), kind=select.type)
330                    for select in scope.expression.selects
331                ],
332                nested=True,
333            )
334
335            if not any(
336                cd.kind.is_type(exp.DataType.Type.UNKNOWN)
337                for cd in struct_type.expressions
338                if cd.kind
339            ):
340                # We don't use `_set_type` on purpose here. If we annotated the query directly, then
341                # using it in other contexts (e.g., ARRAY(<query>)) could result in incorrect type
342                # annotations, i.e., it shouldn't be interpreted as a STRUCT value.
343                scope.expression.meta["query_type"] = struct_type
344
345    def _maybe_annotate(self, expression: E) -> E:
346        if id(expression) in self._visited:
347            return expression  # We've already inferred the expression's type
348
349        annotator = self.annotators.get(expression.__class__)
350
351        return (
352            annotator(self, expression)
353            if annotator
354            else self._annotate_with_type(expression, exp.DataType.Type.UNKNOWN)
355        )
356
357    def _annotate_args(self, expression: E) -> E:
358        for value in expression.iter_expressions():
359            self._maybe_annotate(value)
360
361        return expression
362
363    def _maybe_coerce(
364        self,
365        type1: exp.DataType | exp.DataType.Type,
366        type2: exp.DataType | exp.DataType.Type,
367    ) -> exp.DataType | exp.DataType.Type:
368        """
369        Returns type2 if type1 can be coerced into it, otherwise type1.
370
371        If either type is parameterized (e.g. DECIMAL(18, 2) contains two parameters),
372        we assume type1 does not coerce into type2, so we also return it in this case.
373        """
374        if isinstance(type1, exp.DataType):
375            if type1.expressions:
376                return type1
377            type1_value = type1.this
378        else:
379            type1_value = type1
380
381        if isinstance(type2, exp.DataType):
382            if type2.expressions:
383                return type2
384            type2_value = type2.this
385        else:
386            type2_value = type2
387
388        # We propagate the UNKNOWN type upwards if found
389        if exp.DataType.Type.UNKNOWN in (type1_value, type2_value):
390            return exp.DataType.Type.UNKNOWN
391
392        return type2_value if type2_value in self.coerces_to.get(type1_value, {}) else type1_value
393
394    def _annotate_binary(self, expression: B) -> B:
395        self._annotate_args(expression)
396
397        left, right = expression.left, expression.right
398        left_type, right_type = left.type.this, right.type.this  # type: ignore
399
400        if isinstance(expression, (exp.Connector, exp.Predicate)):
401            self._set_type(expression, exp.DataType.Type.BOOLEAN)
402        elif (left_type, right_type) in self.binary_coercions:
403            self._set_type(expression, self.binary_coercions[(left_type, right_type)](left, right))
404        else:
405            self._set_type(expression, self._maybe_coerce(left_type, right_type))
406
407        return expression
408
409    def _annotate_unary(self, expression: E) -> E:
410        self._annotate_args(expression)
411
412        if isinstance(expression, exp.Not):
413            self._set_type(expression, exp.DataType.Type.BOOLEAN)
414        else:
415            self._set_type(expression, expression.this.type)
416
417        return expression
418
419    def _annotate_literal(self, expression: exp.Literal) -> exp.Literal:
420        if expression.is_string:
421            self._set_type(expression, exp.DataType.Type.VARCHAR)
422        elif expression.is_int:
423            self._set_type(expression, exp.DataType.Type.INT)
424        else:
425            self._set_type(expression, exp.DataType.Type.DOUBLE)
426
427        return expression
428
429    def _annotate_with_type(
430        self, expression: E, target_type: exp.DataType | exp.DataType.Type
431    ) -> E:
432        self._set_type(expression, target_type)
433        return self._annotate_args(expression)
434
435    @t.no_type_check
436    def _annotate_by_args(
437        self,
438        expression: E,
439        *args: str,
440        promote: bool = False,
441        array: bool = False,
442    ) -> E:
443        self._annotate_args(expression)
444
445        expressions: t.List[exp.Expression] = []
446        for arg in args:
447            arg_expr = expression.args.get(arg)
448            expressions.extend(expr for expr in ensure_list(arg_expr) if expr)
449
450        last_datatype = None
451        for expr in expressions:
452            expr_type = expr.type
453
454            # Stop at the first nested data type found - we don't want to _maybe_coerce nested types
455            if expr_type.args.get("nested"):
456                last_datatype = expr_type
457                break
458
459            if not expr_type.is_type(exp.DataType.Type.UNKNOWN):
460                last_datatype = self._maybe_coerce(last_datatype or expr_type, expr_type)
461
462        self._set_type(expression, last_datatype or exp.DataType.Type.UNKNOWN)
463
464        if promote:
465            if expression.type.this in exp.DataType.INTEGER_TYPES:
466                self._set_type(expression, exp.DataType.Type.BIGINT)
467            elif expression.type.this in exp.DataType.FLOAT_TYPES:
468                self._set_type(expression, exp.DataType.Type.DOUBLE)
469
470        if array:
471            self._set_type(
472                expression,
473                exp.DataType(
474                    this=exp.DataType.Type.ARRAY, expressions=[expression.type], nested=True
475                ),
476            )
477
478        return expression
479
480    def _annotate_timeunit(
481        self, expression: exp.TimeUnit | exp.DateTrunc
482    ) -> exp.TimeUnit | exp.DateTrunc:
483        self._annotate_args(expression)
484
485        if expression.this.type.this in exp.DataType.TEXT_TYPES:
486            datatype = _coerce_date_literal(expression.this, expression.unit)
487        elif expression.this.type.this in exp.DataType.TEMPORAL_TYPES:
488            datatype = _coerce_date(expression.this, expression.unit)
489        else:
490            datatype = exp.DataType.Type.UNKNOWN
491
492        self._set_type(expression, datatype)
493        return expression
494
495    def _annotate_bracket(self, expression: exp.Bracket) -> exp.Bracket:
496        self._annotate_args(expression)
497
498        bracket_arg = expression.expressions[0]
499        this = expression.this
500
501        if isinstance(bracket_arg, exp.Slice):
502            self._set_type(expression, this.type)
503        elif this.type.is_type(exp.DataType.Type.ARRAY):
504            self._set_type(expression, seq_get(this.type.expressions, 0))
505        elif isinstance(this, (exp.Map, exp.VarMap)) and bracket_arg in this.keys:
506            index = this.keys.index(bracket_arg)
507            value = seq_get(this.values, index)
508            self._set_type(expression, value.type if value else None)
509        else:
510            self._set_type(expression, exp.DataType.Type.UNKNOWN)
511
512        return expression
513
514    def _annotate_div(self, expression: exp.Div) -> exp.Div:
515        self._annotate_args(expression)
516
517        left_type, right_type = expression.left.type.this, expression.right.type.this  # type: ignore
518
519        if (
520            expression.args.get("typed")
521            and left_type in exp.DataType.INTEGER_TYPES
522            and right_type in exp.DataType.INTEGER_TYPES
523        ):
524            self._set_type(expression, exp.DataType.Type.BIGINT)
525        else:
526            self._set_type(expression, self._maybe_coerce(left_type, right_type))
527            if expression.type and expression.type.this not in exp.DataType.REAL_TYPES:
528                self._set_type(
529                    expression, self._maybe_coerce(expression.type, exp.DataType.Type.DOUBLE)
530                )
531
532        return expression
533
534    def _annotate_dot(self, expression: exp.Dot) -> exp.Dot:
535        self._annotate_args(expression)
536        self._set_type(expression, None)
537        this_type = expression.this.type
538
539        if this_type and this_type.is_type(exp.DataType.Type.STRUCT):
540            for e in this_type.expressions:
541                if e.name == expression.expression.name:
542                    self._set_type(expression, e.kind)
543                    break
544
545        return expression
546
547    def _annotate_explode(self, expression: exp.Explode) -> exp.Explode:
548        self._annotate_args(expression)
549        self._set_type(expression, seq_get(expression.this.type.expressions, 0))
550        return expression
551
552    def _annotate_unnest(self, expression: exp.Unnest) -> exp.Unnest:
553        self._annotate_args(expression)
554        child = seq_get(expression.expressions, 0)
555
556        if child and child.is_type(exp.DataType.Type.ARRAY):
557            expr_type = seq_get(child.type.expressions, 0)
558        else:
559            expr_type = None
560
561        self._set_type(expression, expr_type)
562        return expression
563
564    def _annotate_struct_value(
565        self, expression: exp.Expression
566    ) -> t.Optional[exp.DataType] | exp.ColumnDef:
567        alias = expression.args.get("alias")
568        if alias:
569            return exp.ColumnDef(this=alias.copy(), kind=expression.type)
570
571        # Case: key = value or key := value
572        if expression.expression:
573            return exp.ColumnDef(this=expression.this.copy(), kind=expression.expression.type)
574
575        return expression.type
576
577    def _annotate_struct(self, expression: exp.Struct) -> exp.Struct:
578        self._annotate_args(expression)
579        self._set_type(
580            expression,
581            exp.DataType(
582                this=exp.DataType.Type.STRUCT,
583                expressions=[self._annotate_struct_value(expr) for expr in expression.expressions],
584                nested=True,
585            ),
586        )
587        return expression
588
589    @t.overload
590    def _annotate_map(self, expression: exp.Map) -> exp.Map: ...
591
592    @t.overload
593    def _annotate_map(self, expression: exp.VarMap) -> exp.VarMap: ...
594
595    def _annotate_map(self, expression):
596        self._annotate_args(expression)
597
598        keys = expression.args.get("keys")
599        values = expression.args.get("values")
600
601        map_type = exp.DataType(this=exp.DataType.Type.MAP)
602        if isinstance(keys, exp.Array) and isinstance(values, exp.Array):
603            key_type = seq_get(keys.type.expressions, 0) or exp.DataType.Type.UNKNOWN
604            value_type = seq_get(values.type.expressions, 0) or exp.DataType.Type.UNKNOWN
605
606            if key_type != exp.DataType.Type.UNKNOWN and value_type != exp.DataType.Type.UNKNOWN:
607                map_type.set("expressions", [key_type, value_type])
608                map_type.set("nested", True)
609
610        self._set_type(expression, map_type)
611        return expression
612
613    def _annotate_to_map(self, expression: exp.ToMap) -> exp.ToMap:
614        self._annotate_args(expression)
615
616        map_type = exp.DataType(this=exp.DataType.Type.MAP)
617        arg = expression.this
618        if arg.is_type(exp.DataType.Type.STRUCT):
619            for coldef in arg.type.expressions:
620                kind = coldef.kind
621                if kind != exp.DataType.Type.UNKNOWN:
622                    map_type.set("expressions", [exp.DataType.build("varchar"), kind])
623                    map_type.set("nested", True)
624                    break
625
626        self._set_type(expression, map_type)
627        return expression
628
629    def _annotate_extract(self, expression: exp.Extract) -> exp.Extract:
630        self._annotate_args(expression)
631        part = expression.name
632        if part == "TIME":
633            self._set_type(expression, exp.DataType.Type.TIME)
634        elif part == "DATE":
635            self._set_type(expression, exp.DataType.Type.DATE)
636        else:
637            self._set_type(expression, exp.DataType.Type.INT)
638        return expression
639
640    def _annotate_by_array_element(self, expression: exp.Expression) -> exp.Expression:
641        self._annotate_args(expression)
642
643        array_arg = expression.this
644        if array_arg.type.is_type(exp.DataType.Type.ARRAY):
645            element_type = seq_get(array_arg.type.expressions, 0) or exp.DataType.Type.UNKNOWN
646            self._set_type(expression, element_type)
647        else:
648            self._set_type(expression, exp.DataType.Type.UNKNOWN)
649
650        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(this=exp.to_identifier(select.output_name), kind=select.type)
331                    for select in scope.expression.selects
332                ],
333                nested=True,
334            )
335
336            if not any(
337                cd.kind.is_type(exp.DataType.Type.UNKNOWN)
338                for cd in struct_type.expressions
339                if cd.kind
340            ):
341                # We don't use `_set_type` on purpose here. If we annotated the query directly, then
342                # using it in other contexts (e.g., ARRAY(<query>)) could result in incorrect type
343                # annotations, i.e., it shouldn't be interpreted as a STRUCT value.
344                scope.expression.meta["query_type"] = struct_type
345
346    def _maybe_annotate(self, expression: E) -> E:
347        if id(expression) in self._visited:
348            return expression  # We've already inferred the expression's type
349
350        annotator = self.annotators.get(expression.__class__)
351
352        return (
353            annotator(self, expression)
354            if annotator
355            else self._annotate_with_type(expression, exp.DataType.Type.UNKNOWN)
356        )
357
358    def _annotate_args(self, expression: E) -> E:
359        for value in expression.iter_expressions():
360            self._maybe_annotate(value)
361
362        return expression
363
364    def _maybe_coerce(
365        self,
366        type1: exp.DataType | exp.DataType.Type,
367        type2: exp.DataType | exp.DataType.Type,
368    ) -> exp.DataType | exp.DataType.Type:
369        """
370        Returns type2 if type1 can be coerced into it, otherwise type1.
371
372        If either type is parameterized (e.g. DECIMAL(18, 2) contains two parameters),
373        we assume type1 does not coerce into type2, so we also return it in this case.
374        """
375        if isinstance(type1, exp.DataType):
376            if type1.expressions:
377                return type1
378            type1_value = type1.this
379        else:
380            type1_value = type1
381
382        if isinstance(type2, exp.DataType):
383            if type2.expressions:
384                return type2
385            type2_value = type2.this
386        else:
387            type2_value = type2
388
389        # We propagate the UNKNOWN type upwards if found
390        if exp.DataType.Type.UNKNOWN in (type1_value, type2_value):
391            return exp.DataType.Type.UNKNOWN
392
393        return type2_value if type2_value in self.coerces_to.get(type1_value, {}) else type1_value
394
395    def _annotate_binary(self, expression: B) -> B:
396        self._annotate_args(expression)
397
398        left, right = expression.left, expression.right
399        left_type, right_type = left.type.this, right.type.this  # type: ignore
400
401        if isinstance(expression, (exp.Connector, exp.Predicate)):
402            self._set_type(expression, exp.DataType.Type.BOOLEAN)
403        elif (left_type, right_type) in self.binary_coercions:
404            self._set_type(expression, self.binary_coercions[(left_type, right_type)](left, right))
405        else:
406            self._set_type(expression, self._maybe_coerce(left_type, right_type))
407
408        return expression
409
410    def _annotate_unary(self, expression: E) -> E:
411        self._annotate_args(expression)
412
413        if isinstance(expression, exp.Not):
414            self._set_type(expression, exp.DataType.Type.BOOLEAN)
415        else:
416            self._set_type(expression, expression.this.type)
417
418        return expression
419
420    def _annotate_literal(self, expression: exp.Literal) -> exp.Literal:
421        if expression.is_string:
422            self._set_type(expression, exp.DataType.Type.VARCHAR)
423        elif expression.is_int:
424            self._set_type(expression, exp.DataType.Type.INT)
425        else:
426            self._set_type(expression, exp.DataType.Type.DOUBLE)
427
428        return expression
429
430    def _annotate_with_type(
431        self, expression: E, target_type: exp.DataType | exp.DataType.Type
432    ) -> E:
433        self._set_type(expression, target_type)
434        return self._annotate_args(expression)
435
436    @t.no_type_check
437    def _annotate_by_args(
438        self,
439        expression: E,
440        *args: str,
441        promote: bool = False,
442        array: bool = False,
443    ) -> E:
444        self._annotate_args(expression)
445
446        expressions: t.List[exp.Expression] = []
447        for arg in args:
448            arg_expr = expression.args.get(arg)
449            expressions.extend(expr for expr in ensure_list(arg_expr) if expr)
450
451        last_datatype = None
452        for expr in expressions:
453            expr_type = expr.type
454
455            # Stop at the first nested data type found - we don't want to _maybe_coerce nested types
456            if expr_type.args.get("nested"):
457                last_datatype = expr_type
458                break
459
460            if not expr_type.is_type(exp.DataType.Type.UNKNOWN):
461                last_datatype = self._maybe_coerce(last_datatype or expr_type, expr_type)
462
463        self._set_type(expression, last_datatype or exp.DataType.Type.UNKNOWN)
464
465        if promote:
466            if expression.type.this in exp.DataType.INTEGER_TYPES:
467                self._set_type(expression, exp.DataType.Type.BIGINT)
468            elif expression.type.this in exp.DataType.FLOAT_TYPES:
469                self._set_type(expression, exp.DataType.Type.DOUBLE)
470
471        if array:
472            self._set_type(
473                expression,
474                exp.DataType(
475                    this=exp.DataType.Type.ARRAY, expressions=[expression.type], nested=True
476                ),
477            )
478
479        return expression
480
481    def _annotate_timeunit(
482        self, expression: exp.TimeUnit | exp.DateTrunc
483    ) -> exp.TimeUnit | exp.DateTrunc:
484        self._annotate_args(expression)
485
486        if expression.this.type.this in exp.DataType.TEXT_TYPES:
487            datatype = _coerce_date_literal(expression.this, expression.unit)
488        elif expression.this.type.this in exp.DataType.TEMPORAL_TYPES:
489            datatype = _coerce_date(expression.this, expression.unit)
490        else:
491            datatype = exp.DataType.Type.UNKNOWN
492
493        self._set_type(expression, datatype)
494        return expression
495
496    def _annotate_bracket(self, expression: exp.Bracket) -> exp.Bracket:
497        self._annotate_args(expression)
498
499        bracket_arg = expression.expressions[0]
500        this = expression.this
501
502        if isinstance(bracket_arg, exp.Slice):
503            self._set_type(expression, this.type)
504        elif this.type.is_type(exp.DataType.Type.ARRAY):
505            self._set_type(expression, seq_get(this.type.expressions, 0))
506        elif isinstance(this, (exp.Map, exp.VarMap)) and bracket_arg in this.keys:
507            index = this.keys.index(bracket_arg)
508            value = seq_get(this.values, index)
509            self._set_type(expression, value.type if value else None)
510        else:
511            self._set_type(expression, exp.DataType.Type.UNKNOWN)
512
513        return expression
514
515    def _annotate_div(self, expression: exp.Div) -> exp.Div:
516        self._annotate_args(expression)
517
518        left_type, right_type = expression.left.type.this, expression.right.type.this  # type: ignore
519
520        if (
521            expression.args.get("typed")
522            and left_type in exp.DataType.INTEGER_TYPES
523            and right_type in exp.DataType.INTEGER_TYPES
524        ):
525            self._set_type(expression, exp.DataType.Type.BIGINT)
526        else:
527            self._set_type(expression, self._maybe_coerce(left_type, right_type))
528            if expression.type and expression.type.this not in exp.DataType.REAL_TYPES:
529                self._set_type(
530                    expression, self._maybe_coerce(expression.type, exp.DataType.Type.DOUBLE)
531                )
532
533        return expression
534
535    def _annotate_dot(self, expression: exp.Dot) -> exp.Dot:
536        self._annotate_args(expression)
537        self._set_type(expression, None)
538        this_type = expression.this.type
539
540        if this_type and this_type.is_type(exp.DataType.Type.STRUCT):
541            for e in this_type.expressions:
542                if e.name == expression.expression.name:
543                    self._set_type(expression, e.kind)
544                    break
545
546        return expression
547
548    def _annotate_explode(self, expression: exp.Explode) -> exp.Explode:
549        self._annotate_args(expression)
550        self._set_type(expression, seq_get(expression.this.type.expressions, 0))
551        return expression
552
553    def _annotate_unnest(self, expression: exp.Unnest) -> exp.Unnest:
554        self._annotate_args(expression)
555        child = seq_get(expression.expressions, 0)
556
557        if child and child.is_type(exp.DataType.Type.ARRAY):
558            expr_type = seq_get(child.type.expressions, 0)
559        else:
560            expr_type = None
561
562        self._set_type(expression, expr_type)
563        return expression
564
565    def _annotate_struct_value(
566        self, expression: exp.Expression
567    ) -> t.Optional[exp.DataType] | exp.ColumnDef:
568        alias = expression.args.get("alias")
569        if alias:
570            return exp.ColumnDef(this=alias.copy(), kind=expression.type)
571
572        # Case: key = value or key := value
573        if expression.expression:
574            return exp.ColumnDef(this=expression.this.copy(), kind=expression.expression.type)
575
576        return expression.type
577
578    def _annotate_struct(self, expression: exp.Struct) -> exp.Struct:
579        self._annotate_args(expression)
580        self._set_type(
581            expression,
582            exp.DataType(
583                this=exp.DataType.Type.STRUCT,
584                expressions=[self._annotate_struct_value(expr) for expr in expression.expressions],
585                nested=True,
586            ),
587        )
588        return expression
589
590    @t.overload
591    def _annotate_map(self, expression: exp.Map) -> exp.Map: ...
592
593    @t.overload
594    def _annotate_map(self, expression: exp.VarMap) -> exp.VarMap: ...
595
596    def _annotate_map(self, expression):
597        self._annotate_args(expression)
598
599        keys = expression.args.get("keys")
600        values = expression.args.get("values")
601
602        map_type = exp.DataType(this=exp.DataType.Type.MAP)
603        if isinstance(keys, exp.Array) and isinstance(values, exp.Array):
604            key_type = seq_get(keys.type.expressions, 0) or exp.DataType.Type.UNKNOWN
605            value_type = seq_get(values.type.expressions, 0) or exp.DataType.Type.UNKNOWN
606
607            if key_type != exp.DataType.Type.UNKNOWN and value_type != exp.DataType.Type.UNKNOWN:
608                map_type.set("expressions", [key_type, value_type])
609                map_type.set("nested", True)
610
611        self._set_type(expression, map_type)
612        return expression
613
614    def _annotate_to_map(self, expression: exp.ToMap) -> exp.ToMap:
615        self._annotate_args(expression)
616
617        map_type = exp.DataType(this=exp.DataType.Type.MAP)
618        arg = expression.this
619        if arg.is_type(exp.DataType.Type.STRUCT):
620            for coldef in arg.type.expressions:
621                kind = coldef.kind
622                if kind != exp.DataType.Type.UNKNOWN:
623                    map_type.set("expressions", [exp.DataType.build("varchar"), kind])
624                    map_type.set("nested", True)
625                    break
626
627        self._set_type(expression, map_type)
628        return expression
629
630    def _annotate_extract(self, expression: exp.Extract) -> exp.Extract:
631        self._annotate_args(expression)
632        part = expression.name
633        if part == "TIME":
634            self._set_type(expression, exp.DataType.Type.TIME)
635        elif part == "DATE":
636            self._set_type(expression, exp.DataType.Type.DATE)
637        else:
638            self._set_type(expression, exp.DataType.Type.INT)
639        return expression
640
641    def _annotate_by_array_element(self, expression: exp.Expression) -> exp.Expression:
642        self._annotate_args(expression)
643
644        array_arg = expression.this
645        if array_arg.type.is_type(exp.DataType.Type.ARRAY):
646            element_type = seq_get(array_arg.type.expressions, 0) or exp.DataType.Type.UNKNOWN
647            self._set_type(expression, element_type)
648        else:
649            self._set_type(expression, exp.DataType.Type.UNKNOWN)
650
651        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.TEXT: 'TEXT'>, <Type.NVARCHAR: 'NVARCHAR'>}, <Type.NCHAR: 'NCHAR'>: {<Type.TEXT: 'TEXT'>, <Type.VARCHAR: 'VARCHAR'>, <Type.NVARCHAR: 'NVARCHAR'>}, <Type.CHAR: 'CHAR'>: {<Type.TEXT: 'TEXT'>, <Type.VARCHAR: 'VARCHAR'>, <Type.NVARCHAR: 'NVARCHAR'>, <Type.NCHAR: 'NCHAR'>}, <Type.DOUBLE: 'DOUBLE'>: set(), <Type.FLOAT: 'FLOAT'>: {<Type.DOUBLE: 'DOUBLE'>}, <Type.DECIMAL: 'DECIMAL'>: {<Type.DOUBLE: 'DOUBLE'>, <Type.FLOAT: 'FLOAT'>}, <Type.BIGINT: 'BIGINT'>: {<Type.DECIMAL: 'DECIMAL'>, <Type.DOUBLE: 'DOUBLE'>, <Type.FLOAT: 'FLOAT'>}, <Type.INT: 'INT'>: {<Type.DECIMAL: 'DECIMAL'>, <Type.DOUBLE: 'DOUBLE'>, <Type.FLOAT: 'FLOAT'>, <Type.BIGINT: 'BIGINT'>}, <Type.SMALLINT: 'SMALLINT'>: {<Type.INT: 'INT'>, <Type.BIGINT: 'BIGINT'>, <Type.DECIMAL: 'DECIMAL'>, <Type.DOUBLE: 'DOUBLE'>, <Type.FLOAT: 'FLOAT'>}, <Type.TINYINT: 'TINYINT'>: {<Type.INT: 'INT'>, <Type.BIGINT: 'BIGINT'>, <Type.DECIMAL: 'DECIMAL'>, <Type.DOUBLE: 'DOUBLE'>, <Type.FLOAT: 'FLOAT'>, <Type.SMALLINT: 'SMALLINT'>}, <Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>: set(), <Type.TIMESTAMPTZ: 'TIMESTAMPTZ'>: {<Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>}, <Type.TIMESTAMP: 'TIMESTAMP'>: {<Type.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>}, <Type.DATETIME: 'DATETIME'>: {<Type.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <Type.TIMESTAMP: 'TIMESTAMP'>}, <Type.DATE: 'DATE'>: {<Type.DATETIME: 'DATETIME'>, <Type.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <Type.TIMESTAMP: 'TIMESTAMP'>}, <Type.NULL: 'NULL'>: {<Type.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <Type.TIMESTAMP: 'TIMESTAMP'>, <Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <Type.NVARCHAR: 'NVARCHAR'>, <Type.DECIMAL: 'DECIMAL'>, <Type.INT: 'INT'>, <Type.CHAR: 'CHAR'>, <Type.NCHAR: 'NCHAR'>, <Type.VARCHAR: 'VARCHAR'>, <Type.DOUBLE: 'DOUBLE'>, <Type.BIGINT: 'BIGINT'>, <Type.DATE: 'DATE'>, <Type.DATETIME: 'DATETIME'>, <Type.SMALLINT: 'SMALLINT'>, <Type.TINYINT: 'TINYINT'>, <Type.TEXT: 'TEXT'>, <Type.FLOAT: 'FLOAT'>}}
BINARY_COERCIONS: Dict[Tuple[sqlglot.expressions.DataType.Type, sqlglot.expressions.DataType.Type], Callable[[sqlglot.expressions.Expression, sqlglot.expressions.Expression], sqlglot.expressions.DataType.Type]] = {(<Type.NVARCHAR: 'NVARCHAR'>, <Type.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <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.INTERVAL: 'INTERVAL'>, <Type.NVARCHAR: 'NVARCHAR'>): <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.VARCHAR: 'VARCHAR'>): <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.NVARCHAR: 'NVARCHAR'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.DECIMAL256: 'DECIMAL256'>): <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.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.DECIMAL256: 'DECIMAL256'>): <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.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.DECIMAL256: 'DECIMAL256'>): <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.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.DECIMAL256: 'DECIMAL256'>): <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.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.DECIMAL256: 'DECIMAL256'>): <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.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.DECIMAL256: 'DECIMAL256'>): <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.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL64: 'DECIMAL64'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL256: 'DECIMAL256'>, <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.DECIMAL: 'DECIMAL'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLMONEY: 'SMALLMONEY'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT128: 'UINT128'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MONEY: 'MONEY'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDOUBLE: 'UDOUBLE'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UMEDIUMINT: 'UMEDIUMINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL128: 'DECIMAL128'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL64: 'DECIMAL64'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL256: 'DECIMAL256'>, <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.DECIMAL: 'DECIMAL'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLMONEY: 'SMALLMONEY'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT128: 'UINT128'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MONEY: 'MONEY'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDOUBLE: 'UDOUBLE'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UMEDIUMINT: 'UMEDIUMINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL128: 'DECIMAL128'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL64: 'DECIMAL64'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL256: 'DECIMAL256'>, <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.DECIMAL: 'DECIMAL'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLMONEY: 'SMALLMONEY'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT128: 'UINT128'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MONEY: 'MONEY'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDOUBLE: 'UDOUBLE'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UMEDIUMINT: 'UMEDIUMINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL128: 'DECIMAL128'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL64: 'DECIMAL64'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL256: 'DECIMAL256'>, <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.DECIMAL: 'DECIMAL'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLMONEY: 'SMALLMONEY'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT128: 'UINT128'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MONEY: 'MONEY'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDOUBLE: 'UDOUBLE'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UMEDIUMINT: 'UMEDIUMINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL128: 'DECIMAL128'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL64: 'DECIMAL64'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL256: 'DECIMAL256'>, <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.DECIMAL: 'DECIMAL'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLMONEY: 'SMALLMONEY'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT128: 'UINT128'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MONEY: 'MONEY'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDOUBLE: 'UDOUBLE'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UMEDIUMINT: 'UMEDIUMINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL128: 'DECIMAL128'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL64: 'DECIMAL64'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL256: 'DECIMAL256'>, <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.DECIMAL: 'DECIMAL'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLMONEY: 'SMALLMONEY'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT128: 'UINT128'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MONEY: 'MONEY'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDOUBLE: 'UDOUBLE'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UMEDIUMINT: 'UMEDIUMINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL128: 'DECIMAL128'>, <Type.NAME: 'NAME'>): <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(this=exp.to_identifier(select.output_name), kind=select.type)
331                    for select in scope.expression.selects
332                ],
333                nested=True,
334            )
335
336            if not any(
337                cd.kind.is_type(exp.DataType.Type.UNKNOWN)
338                for cd in struct_type.expressions
339                if cd.kind
340            ):
341                # We don't use `_set_type` on purpose here. If we annotated the query directly, then
342                # using it in other contexts (e.g., ARRAY(<query>)) could result in incorrect type
343                # annotations, i.e., it shouldn't be interpreted as a STRUCT value.
344                scope.expression.meta["query_type"] = struct_type