sqlglot.optimizer.annotate_types API documentation

Edit on GitHub

# sqlglot.optimizer.annotate_types

View Source

      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 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: t.Optional[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)
     59
     60    return TypeAnnotator(schema, annotators, coerces_to, dialect=dialect).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        return klass
    132
    133
    134class TypeAnnotator(metaclass=_TypeAnnotator):
    135    NESTED_TYPES = {
    136        exp.DataType.Type.ARRAY,
    137    }
    138
    139    # Specifies what types a given type can be coerced into (autofilled)
    140    COERCES_TO: t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]] = {}
    141
    142    # Coercion functions for binary operations.
    143    # Map of type pairs to a callable that takes both sides of the binary operation and returns the resulting type.
    144    BINARY_COERCIONS: BinaryCoercions = {
    145        **swap_all(
    146            {
    147                (t, exp.DataType.Type.INTERVAL): lambda l, r: _coerce_date_literal(
    148                    l, r.args.get("unit")
    149                )
    150                for t in exp.DataType.TEXT_TYPES
    151            }
    152        ),
    153        **swap_all(
    154            {
    155                # text + numeric will yield the numeric type to match most dialects' semantics
    156                (text, numeric): lambda l, r: t.cast(
    157                    exp.DataType.Type, l.type if l.type in exp.DataType.NUMERIC_TYPES else r.type
    158                )
    159                for text in exp.DataType.TEXT_TYPES
    160                for numeric in exp.DataType.NUMERIC_TYPES
    161            }
    162        ),
    163        **swap_all(
    164            {
    165                (exp.DataType.Type.DATE, exp.DataType.Type.INTERVAL): lambda l, r: _coerce_date(
    166                    l, r.args.get("unit")
    167                ),
    168            }
    169        ),
    170    }
    171
    172    def __init__(
    173        self,
    174        schema: Schema,
    175        annotators: t.Optional[AnnotatorsType] = None,
    176        coerces_to: t.Optional[t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]]] = None,
    177        binary_coercions: t.Optional[BinaryCoercions] = None,
    178        dialect: t.Optional[DialectType] = None,
    179    ) -> None:
    180        self.schema = schema
    181        self.annotators = annotators or Dialect.get_or_raise(dialect).ANNOTATORS
    182        self.coerces_to = coerces_to or self.COERCES_TO
    183        self.binary_coercions = binary_coercions or self.BINARY_COERCIONS
    184
    185        # Caches the ids of annotated sub-Expressions, to ensure we only visit them once
    186        self._visited: t.Set[int] = set()
    187
    188    def _set_type(
    189        self, expression: exp.Expression, target_type: t.Optional[exp.DataType | exp.DataType.Type]
    190    ) -> None:
    191        expression.type = target_type or exp.DataType.Type.UNKNOWN  # type: ignore
    192        self._visited.add(id(expression))
    193
    194    def annotate(self, expression: E) -> E:
    195        for scope in traverse_scope(expression):
    196            self.annotate_scope(scope)
    197        return self._maybe_annotate(expression)  # This takes care of non-traversable expressions
    198
    199    def annotate_scope(self, scope: Scope) -> None:
    200        selects = {}
    201        for name, source in scope.sources.items():
    202            if not isinstance(source, Scope):
    203                continue
    204            if isinstance(source.expression, exp.UDTF):
    205                values = []
    206
    207                if isinstance(source.expression, exp.Lateral):
    208                    if isinstance(source.expression.this, exp.Explode):
    209                        values = [source.expression.this.this]
    210                elif isinstance(source.expression, exp.Unnest):
    211                    values = [source.expression]
    212                else:
    213                    values = source.expression.expressions[0].expressions
    214
    215                if not values:
    216                    continue
    217
    218                selects[name] = {
    219                    alias: column
    220                    for alias, column in zip(
    221                        source.expression.alias_column_names,
    222                        values,
    223                    )
    224                }
    225            else:
    226                selects[name] = {
    227                    select.alias_or_name: select for select in source.expression.selects
    228                }
    229
    230        # First annotate the current scope's column references
    231        for col in scope.columns:
    232            if not col.table:
    233                continue
    234
    235            source = scope.sources.get(col.table)
    236            if isinstance(source, exp.Table):
    237                self._set_type(col, self.schema.get_column_type(source, col))
    238            elif source:
    239                if col.table in selects and col.name in selects[col.table]:
    240                    self._set_type(col, selects[col.table][col.name].type)
    241                elif isinstance(source.expression, exp.Unnest):
    242                    self._set_type(col, source.expression.type)
    243
    244        # Then (possibly) annotate the remaining expressions in the scope
    245        self._maybe_annotate(scope.expression)
    246
    247    def _maybe_annotate(self, expression: E) -> E:
    248        if id(expression) in self._visited:
    249            return expression  # We've already inferred the expression's type
    250
    251        annotator = self.annotators.get(expression.__class__)
    252
    253        return (
    254            annotator(self, expression)
    255            if annotator
    256            else self._annotate_with_type(expression, exp.DataType.Type.UNKNOWN)
    257        )
    258
    259    def _annotate_args(self, expression: E) -> E:
    260        for value in expression.iter_expressions():
    261            self._maybe_annotate(value)
    262
    263        return expression
    264
    265    def _maybe_coerce(
    266        self, type1: exp.DataType | exp.DataType.Type, type2: exp.DataType | exp.DataType.Type
    267    ) -> exp.DataType | exp.DataType.Type:
    268        type1_value = type1.this if isinstance(type1, exp.DataType) else type1
    269        type2_value = type2.this if isinstance(type2, exp.DataType) else type2
    270
    271        # We propagate the NULL / UNKNOWN types upwards if found
    272        if exp.DataType.Type.NULL in (type1_value, type2_value):
    273            return exp.DataType.Type.NULL
    274        if exp.DataType.Type.UNKNOWN in (type1_value, type2_value):
    275            return exp.DataType.Type.UNKNOWN
    276
    277        return type2_value if type2_value in self.coerces_to.get(type1_value, {}) else type1_value
    278
    279    def _annotate_binary(self, expression: B) -> B:
    280        self._annotate_args(expression)
    281
    282        left, right = expression.left, expression.right
    283        left_type, right_type = left.type.this, right.type.this  # type: ignore
    284
    285        if isinstance(expression, exp.Connector):
    286            if left_type == exp.DataType.Type.NULL and right_type == exp.DataType.Type.NULL:
    287                self._set_type(expression, exp.DataType.Type.NULL)
    288            elif exp.DataType.Type.NULL in (left_type, right_type):
    289                self._set_type(
    290                    expression,
    291                    exp.DataType.build("NULLABLE", expressions=exp.DataType.build("BOOLEAN")),
    292                )
    293            else:
    294                self._set_type(expression, exp.DataType.Type.BOOLEAN)
    295        elif isinstance(expression, exp.Predicate):
    296            self._set_type(expression, exp.DataType.Type.BOOLEAN)
    297        elif (left_type, right_type) in self.binary_coercions:
    298            self._set_type(expression, self.binary_coercions[(left_type, right_type)](left, right))
    299        else:
    300            self._set_type(expression, self._maybe_coerce(left_type, right_type))
    301
    302        return expression
    303
    304    def _annotate_unary(self, expression: E) -> E:
    305        self._annotate_args(expression)
    306
    307        if isinstance(expression, exp.Condition) and not isinstance(expression, exp.Paren):
    308            self._set_type(expression, exp.DataType.Type.BOOLEAN)
    309        else:
    310            self._set_type(expression, expression.this.type)
    311
    312        return expression
    313
    314    def _annotate_literal(self, expression: exp.Literal) -> exp.Literal:
    315        if expression.is_string:
    316            self._set_type(expression, exp.DataType.Type.VARCHAR)
    317        elif expression.is_int:
    318            self._set_type(expression, exp.DataType.Type.INT)
    319        else:
    320            self._set_type(expression, exp.DataType.Type.DOUBLE)
    321
    322        return expression
    323
    324    def _annotate_with_type(
    325        self, expression: E, target_type: exp.DataType | exp.DataType.Type
    326    ) -> E:
    327        self._set_type(expression, target_type)
    328        return self._annotate_args(expression)
    329
    330    @t.no_type_check
    331    def _annotate_by_args(
    332        self,
    333        expression: E,
    334        *args: str,
    335        promote: bool = False,
    336        array: bool = False,
    337    ) -> E:
    338        self._annotate_args(expression)
    339
    340        expressions: t.List[exp.Expression] = []
    341        for arg in args:
    342            arg_expr = expression.args.get(arg)
    343            expressions.extend(expr for expr in ensure_list(arg_expr) if expr)
    344
    345        last_datatype = None
    346        for expr in expressions:
    347            expr_type = expr.type
    348
    349            # Stop at the first nested data type found - we don't want to _maybe_coerce nested types
    350            if expr_type.args.get("nested"):
    351                last_datatype = expr_type
    352                break
    353
    354            if not expr_type.is_type(exp.DataType.Type.NULL, exp.DataType.Type.UNKNOWN):
    355                last_datatype = self._maybe_coerce(last_datatype or expr_type, expr_type)
    356
    357        self._set_type(expression, last_datatype or exp.DataType.Type.UNKNOWN)
    358
    359        if promote:
    360            if expression.type.this in exp.DataType.INTEGER_TYPES:
    361                self._set_type(expression, exp.DataType.Type.BIGINT)
    362            elif expression.type.this in exp.DataType.FLOAT_TYPES:
    363                self._set_type(expression, exp.DataType.Type.DOUBLE)
    364
    365        if array:
    366            self._set_type(
    367                expression,
    368                exp.DataType(
    369                    this=exp.DataType.Type.ARRAY, expressions=[expression.type], nested=True
    370                ),
    371            )
    372
    373        return expression
    374
    375    def _annotate_timeunit(
    376        self, expression: exp.TimeUnit | exp.DateTrunc
    377    ) -> exp.TimeUnit | exp.DateTrunc:
    378        self._annotate_args(expression)
    379
    380        if expression.this.type.this in exp.DataType.TEXT_TYPES:
    381            datatype = _coerce_date_literal(expression.this, expression.unit)
    382        elif expression.this.type.this in exp.DataType.TEMPORAL_TYPES:
    383            datatype = _coerce_date(expression.this, expression.unit)
    384        else:
    385            datatype = exp.DataType.Type.UNKNOWN
    386
    387        self._set_type(expression, datatype)
    388        return expression
    389
    390    def _annotate_bracket(self, expression: exp.Bracket) -> exp.Bracket:
    391        self._annotate_args(expression)
    392
    393        bracket_arg = expression.expressions[0]
    394        this = expression.this
    395
    396        if isinstance(bracket_arg, exp.Slice):
    397            self._set_type(expression, this.type)
    398        elif this.type.is_type(exp.DataType.Type.ARRAY):
    399            self._set_type(expression, seq_get(this.type.expressions, 0))
    400        elif isinstance(this, (exp.Map, exp.VarMap)) and bracket_arg in this.keys:
    401            index = this.keys.index(bracket_arg)
    402            value = seq_get(this.values, index)
    403            self._set_type(expression, value.type if value else None)
    404        else:
    405            self._set_type(expression, exp.DataType.Type.UNKNOWN)
    406
    407        return expression
    408
    409    def _annotate_div(self, expression: exp.Div) -> exp.Div:
    410        self._annotate_args(expression)
    411
    412        left_type, right_type = expression.left.type.this, expression.right.type.this  # type: ignore
    413
    414        if (
    415            expression.args.get("typed")
    416            and left_type in exp.DataType.INTEGER_TYPES
    417            and right_type in exp.DataType.INTEGER_TYPES
    418        ):
    419            self._set_type(expression, exp.DataType.Type.BIGINT)
    420        else:
    421            self._set_type(expression, self._maybe_coerce(left_type, right_type))
    422            if expression.type and expression.type.this not in exp.DataType.REAL_TYPES:
    423                self._set_type(
    424                    expression, self._maybe_coerce(expression.type, exp.DataType.Type.DOUBLE)
    425                )
    426
    427        return expression
    428
    429    def _annotate_dot(self, expression: exp.Dot) -> exp.Dot:
    430        self._annotate_args(expression)
    431        self._set_type(expression, None)
    432        this_type = expression.this.type
    433
    434        if this_type and this_type.is_type(exp.DataType.Type.STRUCT):
    435            for e in this_type.expressions:
    436                if e.name == expression.expression.name:
    437                    self._set_type(expression, e.kind)
    438                    break
    439
    440        return expression
    441
    442    def _annotate_explode(self, expression: exp.Explode) -> exp.Explode:
    443        self._annotate_args(expression)
    444        self._set_type(expression, seq_get(expression.this.type.expressions, 0))
    445        return expression
    446
    447    def _annotate_unnest(self, expression: exp.Unnest) -> exp.Unnest:
    448        self._annotate_args(expression)
    449        child = seq_get(expression.expressions, 0)
    450
    451        if child and child.is_type(exp.DataType.Type.ARRAY):
    452            expr_type = seq_get(child.type.expressions, 0)
    453        else:
    454            expr_type = None
    455
    456        self._set_type(expression, expr_type)
    457        return expression
    458
    459    def _annotate_struct_value(
    460        self, expression: exp.Expression
    461    ) -> t.Optional[exp.DataType] | exp.ColumnDef:
    462        alias = expression.args.get("alias")
    463        if alias:
    464            return exp.ColumnDef(this=alias.copy(), kind=expression.type)
    465
    466        # Case: key = value or key := value
    467        if expression.expression:
    468            return exp.ColumnDef(this=expression.this.copy(), kind=expression.expression.type)
    469
    470        return expression.type
    471
    472    def _annotate_struct(self, expression: exp.Struct) -> exp.Struct:
    473        self._annotate_args(expression)
    474        self._set_type(
    475            expression,
    476            exp.DataType(
    477                this=exp.DataType.Type.STRUCT,
    478                expressions=[self._annotate_struct_value(expr) for expr in expression.expressions],
    479                nested=True,
    480            ),
    481        )
    482        return expression
    483
    484    @t.overload
    485    def _annotate_map(self, expression: exp.Map) -> exp.Map: ...
    486
    487    @t.overload
    488    def _annotate_map(self, expression: exp.VarMap) -> exp.VarMap: ...
    489
    490    def _annotate_map(self, expression):
    491        self._annotate_args(expression)
    492
    493        keys = expression.args.get("keys")
    494        values = expression.args.get("values")
    495
    496        map_type = exp.DataType(this=exp.DataType.Type.MAP)
    497        if isinstance(keys, exp.Array) and isinstance(values, exp.Array):
    498            key_type = seq_get(keys.type.expressions, 0) or exp.DataType.Type.UNKNOWN
    499            value_type = seq_get(values.type.expressions, 0) or exp.DataType.Type.UNKNOWN
    500
    501            if key_type != exp.DataType.Type.UNKNOWN and value_type != exp.DataType.Type.UNKNOWN:
    502                map_type.set("expressions", [key_type, value_type])
    503                map_type.set("nested", True)
    504
    505        self._set_type(expression, map_type)
    506        return expression
    507
    508    def _annotate_to_map(self, expression: exp.ToMap) -> exp.ToMap:
    509        self._annotate_args(expression)
    510
    511        map_type = exp.DataType(this=exp.DataType.Type.MAP)
    512        arg = expression.this
    513        if arg.is_type(exp.DataType.Type.STRUCT):
    514            for coldef in arg.type.expressions:
    515                kind = coldef.kind
    516                if kind != exp.DataType.Type.UNKNOWN:
    517                    map_type.set("expressions", [exp.DataType.build("varchar"), kind])
    518                    map_type.set("nested", True)
    519                    break
    520
    521        self._set_type(expression, map_type)
    522        return expression
    523
    524    def _annotate_extract(self, expression: exp.Extract) -> exp.Extract:
    525        self._annotate_args(expression)
    526        part = expression.name
    527        if part == "TIME":
    528            self._set_type(expression, exp.DataType.Type.TIME)
    529        elif part == "DATE":
    530            self._set_type(expression, exp.DataType.Type.DATE)
    531        else:
    532            self._set_type(expression, exp.DataType.Type.INT)
    533        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.Dialect, Type[sqlglot.dialects.dialect.Dialect], NoneType] = None) -> ~E: View Source

    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: t.Optional[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)
    60
    61    return TypeAnnotator(schema, annotators, coerces_to, dialect=dialect).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.

def swap_args( func: Callable[[sqlglot.expressions.Expression, sqlglot.expressions.Expression], sqlglot.expressions.DataType.Type]) -> Callable[[sqlglot.expressions.Expression, sqlglot.expressions.Expression], sqlglot.expressions.DataType.Type]: View Source

    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

def swap_all( coercions: Dict[Tuple[sqlglot.expressions.DataType.Type, sqlglot.expressions.DataType.Type], Callable[[sqlglot.expressions.Expression, sqlglot.expressions.Expression], sqlglot.expressions.DataType.Type]]) -> Dict[Tuple[sqlglot.expressions.DataType.Type, sqlglot.expressions.DataType.Type], Callable[[sqlglot.expressions.Expression, sqlglot.expressions.Expression], sqlglot.expressions.DataType.Type]]: View Source

    92def swap_all(coercions: BinaryCoercions) -> BinaryCoercions:
    93    return {**coercions, **{(b, a): swap_args(func) for (a, b), func in coercions.items()}}

class TypeAnnotator: View Source

    135class TypeAnnotator(metaclass=_TypeAnnotator):
    136    NESTED_TYPES = {
    137        exp.DataType.Type.ARRAY,
    138    }
    139
    140    # Specifies what types a given type can be coerced into (autofilled)
    141    COERCES_TO: t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]] = {}
    142
    143    # Coercion functions for binary operations.
    144    # Map of type pairs to a callable that takes both sides of the binary operation and returns the resulting type.
    145    BINARY_COERCIONS: BinaryCoercions = {
    146        **swap_all(
    147            {
    148                (t, exp.DataType.Type.INTERVAL): lambda l, r: _coerce_date_literal(
    149                    l, r.args.get("unit")
    150                )
    151                for t in exp.DataType.TEXT_TYPES
    152            }
    153        ),
    154        **swap_all(
    155            {
    156                # text + numeric will yield the numeric type to match most dialects' semantics
    157                (text, numeric): lambda l, r: t.cast(
    158                    exp.DataType.Type, l.type if l.type in exp.DataType.NUMERIC_TYPES else r.type
    159                )
    160                for text in exp.DataType.TEXT_TYPES
    161                for numeric in exp.DataType.NUMERIC_TYPES
    162            }
    163        ),
    164        **swap_all(
    165            {
    166                (exp.DataType.Type.DATE, exp.DataType.Type.INTERVAL): lambda l, r: _coerce_date(
    167                    l, r.args.get("unit")
    168                ),
    169            }
    170        ),
    171    }
    172
    173    def __init__(
    174        self,
    175        schema: Schema,
    176        annotators: t.Optional[AnnotatorsType] = None,
    177        coerces_to: t.Optional[t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]]] = None,
    178        binary_coercions: t.Optional[BinaryCoercions] = None,
    179        dialect: t.Optional[DialectType] = None,
    180    ) -> None:
    181        self.schema = schema
    182        self.annotators = annotators or Dialect.get_or_raise(dialect).ANNOTATORS
    183        self.coerces_to = coerces_to or self.COERCES_TO
    184        self.binary_coercions = binary_coercions or self.BINARY_COERCIONS
    185
    186        # Caches the ids of annotated sub-Expressions, to ensure we only visit them once
    187        self._visited: t.Set[int] = set()
    188
    189    def _set_type(
    190        self, expression: exp.Expression, target_type: t.Optional[exp.DataType | exp.DataType.Type]
    191    ) -> None:
    192        expression.type = target_type or exp.DataType.Type.UNKNOWN  # type: ignore
    193        self._visited.add(id(expression))
    194
    195    def annotate(self, expression: E) -> E:
    196        for scope in traverse_scope(expression):
    197            self.annotate_scope(scope)
    198        return self._maybe_annotate(expression)  # This takes care of non-traversable expressions
    199
    200    def annotate_scope(self, scope: Scope) -> None:
    201        selects = {}
    202        for name, source in scope.sources.items():
    203            if not isinstance(source, Scope):
    204                continue
    205            if isinstance(source.expression, exp.UDTF):
    206                values = []
    207
    208                if isinstance(source.expression, exp.Lateral):
    209                    if isinstance(source.expression.this, exp.Explode):
    210                        values = [source.expression.this.this]
    211                elif isinstance(source.expression, exp.Unnest):
    212                    values = [source.expression]
    213                else:
    214                    values = source.expression.expressions[0].expressions
    215
    216                if not values:
    217                    continue
    218
    219                selects[name] = {
    220                    alias: column
    221                    for alias, column in zip(
    222                        source.expression.alias_column_names,
    223                        values,
    224                    )
    225                }
    226            else:
    227                selects[name] = {
    228                    select.alias_or_name: select for select in source.expression.selects
    229                }
    230
    231        # First annotate the current scope's column references
    232        for col in scope.columns:
    233            if not col.table:
    234                continue
    235
    236            source = scope.sources.get(col.table)
    237            if isinstance(source, exp.Table):
    238                self._set_type(col, self.schema.get_column_type(source, col))
    239            elif source:
    240                if col.table in selects and col.name in selects[col.table]:
    241                    self._set_type(col, selects[col.table][col.name].type)
    242                elif isinstance(source.expression, exp.Unnest):
    243                    self._set_type(col, source.expression.type)
    244
    245        # Then (possibly) annotate the remaining expressions in the scope
    246        self._maybe_annotate(scope.expression)
    247
    248    def _maybe_annotate(self, expression: E) -> E:
    249        if id(expression) in self._visited:
    250            return expression  # We've already inferred the expression's type
    251
    252        annotator = self.annotators.get(expression.__class__)
    253
    254        return (
    255            annotator(self, expression)
    256            if annotator
    257            else self._annotate_with_type(expression, exp.DataType.Type.UNKNOWN)
    258        )
    259
    260    def _annotate_args(self, expression: E) -> E:
    261        for value in expression.iter_expressions():
    262            self._maybe_annotate(value)
    263
    264        return expression
    265
    266    def _maybe_coerce(
    267        self, type1: exp.DataType | exp.DataType.Type, type2: exp.DataType | exp.DataType.Type
    268    ) -> exp.DataType | exp.DataType.Type:
    269        type1_value = type1.this if isinstance(type1, exp.DataType) else type1
    270        type2_value = type2.this if isinstance(type2, exp.DataType) else type2
    271
    272        # We propagate the NULL / UNKNOWN types upwards if found
    273        if exp.DataType.Type.NULL in (type1_value, type2_value):
    274            return exp.DataType.Type.NULL
    275        if exp.DataType.Type.UNKNOWN in (type1_value, type2_value):
    276            return exp.DataType.Type.UNKNOWN
    277
    278        return type2_value if type2_value in self.coerces_to.get(type1_value, {}) else type1_value
    279
    280    def _annotate_binary(self, expression: B) -> B:
    281        self._annotate_args(expression)
    282
    283        left, right = expression.left, expression.right
    284        left_type, right_type = left.type.this, right.type.this  # type: ignore
    285
    286        if isinstance(expression, exp.Connector):
    287            if left_type == exp.DataType.Type.NULL and right_type == exp.DataType.Type.NULL:
    288                self._set_type(expression, exp.DataType.Type.NULL)
    289            elif exp.DataType.Type.NULL in (left_type, right_type):
    290                self._set_type(
    291                    expression,
    292                    exp.DataType.build("NULLABLE", expressions=exp.DataType.build("BOOLEAN")),
    293                )
    294            else:
    295                self._set_type(expression, exp.DataType.Type.BOOLEAN)
    296        elif isinstance(expression, exp.Predicate):
    297            self._set_type(expression, exp.DataType.Type.BOOLEAN)
    298        elif (left_type, right_type) in self.binary_coercions:
    299            self._set_type(expression, self.binary_coercions[(left_type, right_type)](left, right))
    300        else:
    301            self._set_type(expression, self._maybe_coerce(left_type, right_type))
    302
    303        return expression
    304
    305    def _annotate_unary(self, expression: E) -> E:
    306        self._annotate_args(expression)
    307
    308        if isinstance(expression, exp.Condition) and not isinstance(expression, exp.Paren):
    309            self._set_type(expression, exp.DataType.Type.BOOLEAN)
    310        else:
    311            self._set_type(expression, expression.this.type)
    312
    313        return expression
    314
    315    def _annotate_literal(self, expression: exp.Literal) -> exp.Literal:
    316        if expression.is_string:
    317            self._set_type(expression, exp.DataType.Type.VARCHAR)
    318        elif expression.is_int:
    319            self._set_type(expression, exp.DataType.Type.INT)
    320        else:
    321            self._set_type(expression, exp.DataType.Type.DOUBLE)
    322
    323        return expression
    324
    325    def _annotate_with_type(
    326        self, expression: E, target_type: exp.DataType | exp.DataType.Type
    327    ) -> E:
    328        self._set_type(expression, target_type)
    329        return self._annotate_args(expression)
    330
    331    @t.no_type_check
    332    def _annotate_by_args(
    333        self,
    334        expression: E,
    335        *args: str,
    336        promote: bool = False,
    337        array: bool = False,
    338    ) -> E:
    339        self._annotate_args(expression)
    340
    341        expressions: t.List[exp.Expression] = []
    342        for arg in args:
    343            arg_expr = expression.args.get(arg)
    344            expressions.extend(expr for expr in ensure_list(arg_expr) if expr)
    345
    346        last_datatype = None
    347        for expr in expressions:
    348            expr_type = expr.type
    349
    350            # Stop at the first nested data type found - we don't want to _maybe_coerce nested types
    351            if expr_type.args.get("nested"):
    352                last_datatype = expr_type
    353                break
    354
    355            if not expr_type.is_type(exp.DataType.Type.NULL, exp.DataType.Type.UNKNOWN):
    356                last_datatype = self._maybe_coerce(last_datatype or expr_type, expr_type)
    357
    358        self._set_type(expression, last_datatype or exp.DataType.Type.UNKNOWN)
    359
    360        if promote:
    361            if expression.type.this in exp.DataType.INTEGER_TYPES:
    362                self._set_type(expression, exp.DataType.Type.BIGINT)
    363            elif expression.type.this in exp.DataType.FLOAT_TYPES:
    364                self._set_type(expression, exp.DataType.Type.DOUBLE)
    365
    366        if array:
    367            self._set_type(
    368                expression,
    369                exp.DataType(
    370                    this=exp.DataType.Type.ARRAY, expressions=[expression.type], nested=True
    371                ),
    372            )
    373
    374        return expression
    375
    376    def _annotate_timeunit(
    377        self, expression: exp.TimeUnit | exp.DateTrunc
    378    ) -> exp.TimeUnit | exp.DateTrunc:
    379        self._annotate_args(expression)
    380
    381        if expression.this.type.this in exp.DataType.TEXT_TYPES:
    382            datatype = _coerce_date_literal(expression.this, expression.unit)
    383        elif expression.this.type.this in exp.DataType.TEMPORAL_TYPES:
    384            datatype = _coerce_date(expression.this, expression.unit)
    385        else:
    386            datatype = exp.DataType.Type.UNKNOWN
    387
    388        self._set_type(expression, datatype)
    389        return expression
    390
    391    def _annotate_bracket(self, expression: exp.Bracket) -> exp.Bracket:
    392        self._annotate_args(expression)
    393
    394        bracket_arg = expression.expressions[0]
    395        this = expression.this
    396
    397        if isinstance(bracket_arg, exp.Slice):
    398            self._set_type(expression, this.type)
    399        elif this.type.is_type(exp.DataType.Type.ARRAY):
    400            self._set_type(expression, seq_get(this.type.expressions, 0))
    401        elif isinstance(this, (exp.Map, exp.VarMap)) and bracket_arg in this.keys:
    402            index = this.keys.index(bracket_arg)
    403            value = seq_get(this.values, index)
    404            self._set_type(expression, value.type if value else None)
    405        else:
    406            self._set_type(expression, exp.DataType.Type.UNKNOWN)
    407
    408        return expression
    409
    410    def _annotate_div(self, expression: exp.Div) -> exp.Div:
    411        self._annotate_args(expression)
    412
    413        left_type, right_type = expression.left.type.this, expression.right.type.this  # type: ignore
    414
    415        if (
    416            expression.args.get("typed")
    417            and left_type in exp.DataType.INTEGER_TYPES
    418            and right_type in exp.DataType.INTEGER_TYPES
    419        ):
    420            self._set_type(expression, exp.DataType.Type.BIGINT)
    421        else:
    422            self._set_type(expression, self._maybe_coerce(left_type, right_type))
    423            if expression.type and expression.type.this not in exp.DataType.REAL_TYPES:
    424                self._set_type(
    425                    expression, self._maybe_coerce(expression.type, exp.DataType.Type.DOUBLE)
    426                )
    427
    428        return expression
    429
    430    def _annotate_dot(self, expression: exp.Dot) -> exp.Dot:
    431        self._annotate_args(expression)
    432        self._set_type(expression, None)
    433        this_type = expression.this.type
    434
    435        if this_type and this_type.is_type(exp.DataType.Type.STRUCT):
    436            for e in this_type.expressions:
    437                if e.name == expression.expression.name:
    438                    self._set_type(expression, e.kind)
    439                    break
    440
    441        return expression
    442
    443    def _annotate_explode(self, expression: exp.Explode) -> exp.Explode:
    444        self._annotate_args(expression)
    445        self._set_type(expression, seq_get(expression.this.type.expressions, 0))
    446        return expression
    447
    448    def _annotate_unnest(self, expression: exp.Unnest) -> exp.Unnest:
    449        self._annotate_args(expression)
    450        child = seq_get(expression.expressions, 0)
    451
    452        if child and child.is_type(exp.DataType.Type.ARRAY):
    453            expr_type = seq_get(child.type.expressions, 0)
    454        else:
    455            expr_type = None
    456
    457        self._set_type(expression, expr_type)
    458        return expression
    459
    460    def _annotate_struct_value(
    461        self, expression: exp.Expression
    462    ) -> t.Optional[exp.DataType] | exp.ColumnDef:
    463        alias = expression.args.get("alias")
    464        if alias:
    465            return exp.ColumnDef(this=alias.copy(), kind=expression.type)
    466
    467        # Case: key = value or key := value
    468        if expression.expression:
    469            return exp.ColumnDef(this=expression.this.copy(), kind=expression.expression.type)
    470
    471        return expression.type
    472
    473    def _annotate_struct(self, expression: exp.Struct) -> exp.Struct:
    474        self._annotate_args(expression)
    475        self._set_type(
    476            expression,
    477            exp.DataType(
    478                this=exp.DataType.Type.STRUCT,
    479                expressions=[self._annotate_struct_value(expr) for expr in expression.expressions],
    480                nested=True,
    481            ),
    482        )
    483        return expression
    484
    485    @t.overload
    486    def _annotate_map(self, expression: exp.Map) -> exp.Map: ...
    487
    488    @t.overload
    489    def _annotate_map(self, expression: exp.VarMap) -> exp.VarMap: ...
    490
    491    def _annotate_map(self, expression):
    492        self._annotate_args(expression)
    493
    494        keys = expression.args.get("keys")
    495        values = expression.args.get("values")
    496
    497        map_type = exp.DataType(this=exp.DataType.Type.MAP)
    498        if isinstance(keys, exp.Array) and isinstance(values, exp.Array):
    499            key_type = seq_get(keys.type.expressions, 0) or exp.DataType.Type.UNKNOWN
    500            value_type = seq_get(values.type.expressions, 0) or exp.DataType.Type.UNKNOWN
    501
    502            if key_type != exp.DataType.Type.UNKNOWN and value_type != exp.DataType.Type.UNKNOWN:
    503                map_type.set("expressions", [key_type, value_type])
    504                map_type.set("nested", True)
    505
    506        self._set_type(expression, map_type)
    507        return expression
    508
    509    def _annotate_to_map(self, expression: exp.ToMap) -> exp.ToMap:
    510        self._annotate_args(expression)
    511
    512        map_type = exp.DataType(this=exp.DataType.Type.MAP)
    513        arg = expression.this
    514        if arg.is_type(exp.DataType.Type.STRUCT):
    515            for coldef in arg.type.expressions:
    516                kind = coldef.kind
    517                if kind != exp.DataType.Type.UNKNOWN:
    518                    map_type.set("expressions", [exp.DataType.build("varchar"), kind])
    519                    map_type.set("nested", True)
    520                    break
    521
    522        self._set_type(expression, map_type)
    523        return expression
    524
    525    def _annotate_extract(self, expression: exp.Extract) -> exp.Extract:
    526        self._annotate_args(expression)
    527        part = expression.name
    528        if part == "TIME":
    529            self._set_type(expression, exp.DataType.Type.TIME)
    530        elif part == "DATE":
    531            self._set_type(expression, exp.DataType.Type.DATE)
    532        else:
    533            self._set_type(expression, exp.DataType.Type.INT)
    534        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, dialect: Union[str, sqlglot.dialects.dialect.Dialect, Type[sqlglot.dialects.dialect.Dialect], NoneType] = None) View Source

    173    def __init__(
    174        self,
    175        schema: Schema,
    176        annotators: t.Optional[AnnotatorsType] = None,
    177        coerces_to: t.Optional[t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]]] = None,
    178        binary_coercions: t.Optional[BinaryCoercions] = None,
    179        dialect: t.Optional[DialectType] = None,
    180    ) -> None:
    181        self.schema = schema
    182        self.annotators = annotators or Dialect.get_or_raise(dialect).ANNOTATORS
    183        self.coerces_to = coerces_to or self.COERCES_TO
    184        self.binary_coercions = binary_coercions or self.BINARY_COERCIONS
    185
    186        # Caches the ids of annotated sub-Expressions, to ensure we only visit them once
    187        self._visited: t.Set[int] = set()

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.NCHAR: 'NCHAR'>, <Type.NVARCHAR: 'NVARCHAR'>, <Type.TEXT: 'TEXT'>, <Type.VARCHAR: 'VARCHAR'>}, <Type.DOUBLE: 'DOUBLE'>: set(), <Type.FLOAT: 'FLOAT'>: {<Type.DOUBLE: 'DOUBLE'>}, <Type.DECIMAL: 'DECIMAL'>: {<Type.DOUBLE: 'DOUBLE'>, <Type.FLOAT: 'FLOAT'>}, <Type.BIGINT: 'BIGINT'>: {<Type.DECIMAL: 'DECIMAL'>, <Type.DOUBLE: 'DOUBLE'>, <Type.FLOAT: 'FLOAT'>}, <Type.INT: 'INT'>: {<Type.DECIMAL: 'DECIMAL'>, <Type.DOUBLE: 'DOUBLE'>, <Type.BIGINT: 'BIGINT'>, <Type.FLOAT: 'FLOAT'>}, <Type.SMALLINT: 'SMALLINT'>: {<Type.BIGINT: 'BIGINT'>, <Type.DECIMAL: 'DECIMAL'>, <Type.DOUBLE: 'DOUBLE'>, <Type.FLOAT: 'FLOAT'>, <Type.INT: 'INT'>}, <Type.TINYINT: 'TINYINT'>: {<Type.BIGINT: 'BIGINT'>, <Type.SMALLINT: 'SMALLINT'>, <Type.DECIMAL: 'DECIMAL'>, <Type.DOUBLE: 'DOUBLE'>, <Type.FLOAT: 'FLOAT'>, <Type.INT: 'INT'>}, <Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>: set(), <Type.TIMESTAMPTZ: 'TIMESTAMPTZ'>: {<Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>}, <Type.TIMESTAMP: 'TIMESTAMP'>: {<Type.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>}, <Type.DATETIME: 'DATETIME'>: {<Type.TIMESTAMP: 'TIMESTAMP'>, <Type.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>}, <Type.DATE: 'DATE'>: {<Type.TIMESTAMP: 'TIMESTAMP'>, <Type.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <Type.DATETIME: 'DATETIME'>, <Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>}}
BINARY_COERCIONS: Dict[Tuple[sqlglot.expressions.DataType.Type, sqlglot.expressions.DataType.Type], Callable[[sqlglot.expressions.Expression, sqlglot.expressions.Expression], sqlglot.expressions.DataType.Type]] = {(<Type.TEXT: 'TEXT'>, <Type.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <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.NCHAR: 'NCHAR'>, <Type.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INTERVAL: 'INTERVAL'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INTERVAL: 'INTERVAL'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INTERVAL: 'INTERVAL'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INTERVAL: 'INTERVAL'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INTERVAL: 'INTERVAL'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INTERVAL: 'INTERVAL'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UTINYINT: 'UTINYINT'>): <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.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UINT256: 'UINT256'>): <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.NVARCHAR: 'NVARCHAR'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UTINYINT: 'UTINYINT'>): <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.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UINT256: 'UINT256'>): <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.CHAR: 'CHAR'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UTINYINT: 'UTINYINT'>): <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.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UINT256: 'UINT256'>): <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.VARCHAR: 'VARCHAR'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UTINYINT: 'UTINYINT'>): <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.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UINT256: 'UINT256'>): <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.NCHAR: 'NCHAR'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UTINYINT: 'UTINYINT'>): <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.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UINT256: 'UINT256'>): <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.NAME: 'NAME'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UTINYINT: 'UTINYINT'>): <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.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UINT256: 'UINT256'>): <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.SMALLMONEY: 'SMALLMONEY'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL: 'DECIMAL'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT: 'UINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <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.UINT128: 'UINT128'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <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.SMALLMONEY: 'SMALLMONEY'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL: 'DECIMAL'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT: 'UINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <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.UINT128: 'UINT128'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <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.SMALLMONEY: 'SMALLMONEY'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL: 'DECIMAL'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT: 'UINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <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.UINT128: 'UINT128'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <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.SMALLMONEY: 'SMALLMONEY'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL: 'DECIMAL'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT: 'UINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <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.UINT128: 'UINT128'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <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.SMALLMONEY: 'SMALLMONEY'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL: 'DECIMAL'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT: 'UINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <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.UINT128: 'UINT128'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <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.SMALLMONEY: 'SMALLMONEY'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL: 'DECIMAL'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT: 'UINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <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.UINT128: 'UINT128'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <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.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: View Source

    195    def annotate(self, expression: E) -> E:
    196        for scope in traverse_scope(expression):
    197            self.annotate_scope(scope)
    198        return self._maybe_annotate(expression)  # This takes care of non-traversable expressions

def annotate_scope(self, scope: sqlglot.optimizer.scope.Scope) -> None: View Source

    200    def annotate_scope(self, scope: Scope) -> None:
    201        selects = {}
    202        for name, source in scope.sources.items():
    203            if not isinstance(source, Scope):
    204                continue
    205            if isinstance(source.expression, exp.UDTF):
    206                values = []
    207
    208                if isinstance(source.expression, exp.Lateral):
    209                    if isinstance(source.expression.this, exp.Explode):
    210                        values = [source.expression.this.this]
    211                elif isinstance(source.expression, exp.Unnest):
    212                    values = [source.expression]
    213                else:
    214                    values = source.expression.expressions[0].expressions
    215
    216                if not values:
    217                    continue
    218
    219                selects[name] = {
    220                    alias: column
    221                    for alias, column in zip(
    222                        source.expression.alias_column_names,
    223                        values,
    224                    )
    225                }
    226            else:
    227                selects[name] = {
    228                    select.alias_or_name: select for select in source.expression.selects
    229                }
    230
    231        # First annotate the current scope's column references
    232        for col in scope.columns:
    233            if not col.table:
    234                continue
    235
    236            source = scope.sources.get(col.table)
    237            if isinstance(source, exp.Table):
    238                self._set_type(col, self.schema.get_column_type(source, col))
    239            elif source:
    240                if col.table in selects and col.name in selects[col.table]:
    241                    self._set_type(col, selects[col.table][col.name].type)
    242                elif isinstance(source.expression, exp.Unnest):
    243                    self._set_type(col, source.expression.type)
    244
    245        # Then (possibly) annotate the remaining expressions in the scope
    246        self._maybe_annotate(scope.expression)