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