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._typing import E
  8from sqlglot.helper import (
  9    ensure_list,
 10    is_date_unit,
 11    is_iso_date,
 12    is_iso_datetime,
 13    seq_get,
 14    subclasses,
 15)
 16from sqlglot.optimizer.scope import Scope, traverse_scope
 17from sqlglot.schema import Schema, ensure_schema
 18
 19if t.TYPE_CHECKING:
 20    B = t.TypeVar("B", bound=exp.Binary)
 21
 22    BinaryCoercionFunc = t.Callable[[exp.Expression, exp.Expression], exp.DataType.Type]
 23    BinaryCoercions = t.Dict[
 24        t.Tuple[exp.DataType.Type, exp.DataType.Type],
 25        BinaryCoercionFunc,
 26    ]
 27
 28
 29def annotate_types(
 30    expression: E,
 31    schema: t.Optional[t.Dict | Schema] = None,
 32    annotators: t.Optional[t.Dict[t.Type[E], t.Callable[[TypeAnnotator, E], E]]] = None,
 33    coerces_to: t.Optional[t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]]] = None,
 34) -> E:
 35    """
 36    Infers the types of an expression, annotating its AST accordingly.
 37
 38    Example:
 39        >>> import sqlglot
 40        >>> schema = {"y": {"cola": "SMALLINT"}}
 41        >>> sql = "SELECT x.cola + 2.5 AS cola FROM (SELECT y.cola AS cola FROM y AS y) AS x"
 42        >>> annotated_expr = annotate_types(sqlglot.parse_one(sql), schema=schema)
 43        >>> annotated_expr.expressions[0].type.this  # Get the type of "x.cola + 2.5 AS cola"
 44        <Type.DOUBLE: 'DOUBLE'>
 45
 46    Args:
 47        expression: Expression to annotate.
 48        schema: Database schema.
 49        annotators: Maps expression type to corresponding annotation function.
 50        coerces_to: Maps expression type to set of types that it can be coerced into.
 51
 52    Returns:
 53        The expression annotated with types.
 54    """
 55
 56    schema = ensure_schema(schema)
 57
 58    return TypeAnnotator(schema, annotators, coerces_to).annotate(expression)
 59
 60
 61def _annotate_with_type_lambda(data_type: exp.DataType.Type) -> t.Callable[[TypeAnnotator, E], E]:
 62    return lambda self, e: self._annotate_with_type(e, data_type)
 63
 64
 65def _coerce_date_literal(l: exp.Expression, unit: t.Optional[exp.Expression]) -> exp.DataType.Type:
 66    date_text = l.name
 67    is_iso_date_ = is_iso_date(date_text)
 68
 69    if is_iso_date_ and is_date_unit(unit):
 70        return exp.DataType.Type.DATE
 71
 72    # An ISO date is also an ISO datetime, but not vice versa
 73    if is_iso_date_ or is_iso_datetime(date_text):
 74        return exp.DataType.Type.DATETIME
 75
 76    return exp.DataType.Type.UNKNOWN
 77
 78
 79def _coerce_date(l: exp.Expression, unit: t.Optional[exp.Expression]) -> exp.DataType.Type:
 80    if not is_date_unit(unit):
 81        return exp.DataType.Type.DATETIME
 82    return l.type.this if l.type else exp.DataType.Type.UNKNOWN
 83
 84
 85def swap_args(func: BinaryCoercionFunc) -> BinaryCoercionFunc:
 86    @functools.wraps(func)
 87    def _swapped(l: exp.Expression, r: exp.Expression) -> exp.DataType.Type:
 88        return func(r, l)
 89
 90    return _swapped
 91
 92
 93def swap_all(coercions: BinaryCoercions) -> BinaryCoercions:
 94    return {**coercions, **{(b, a): swap_args(func) for (a, b), func in coercions.items()}}
 95
 96
 97class _TypeAnnotator(type):
 98    def __new__(cls, clsname, bases, attrs):
 99        klass = super().__new__(cls, clsname, bases, attrs)
100
101        # Highest-to-lowest type precedence, as specified in Spark's docs (ANSI):
102        # https://spark.apache.org/docs/3.2.0/sql-ref-ansi-compliance.html
103        text_precedence = (
104            exp.DataType.Type.TEXT,
105            exp.DataType.Type.NVARCHAR,
106            exp.DataType.Type.VARCHAR,
107            exp.DataType.Type.NCHAR,
108            exp.DataType.Type.CHAR,
109        )
110        numeric_precedence = (
111            exp.DataType.Type.DOUBLE,
112            exp.DataType.Type.FLOAT,
113            exp.DataType.Type.DECIMAL,
114            exp.DataType.Type.BIGINT,
115            exp.DataType.Type.INT,
116            exp.DataType.Type.SMALLINT,
117            exp.DataType.Type.TINYINT,
118        )
119        timelike_precedence = (
120            exp.DataType.Type.TIMESTAMPLTZ,
121            exp.DataType.Type.TIMESTAMPTZ,
122            exp.DataType.Type.TIMESTAMP,
123            exp.DataType.Type.DATETIME,
124            exp.DataType.Type.DATE,
125        )
126
127        for type_precedence in (text_precedence, numeric_precedence, timelike_precedence):
128            coerces_to = set()
129            for data_type in type_precedence:
130                klass.COERCES_TO[data_type] = coerces_to.copy()
131                coerces_to |= {data_type}
132
133        return klass
134
135
136class TypeAnnotator(metaclass=_TypeAnnotator):
137    TYPE_TO_EXPRESSIONS: t.Dict[exp.DataType.Type, t.Set[t.Type[exp.Expression]]] = {
138        exp.DataType.Type.BIGINT: {
139            exp.ApproxDistinct,
140            exp.ArraySize,
141            exp.Count,
142            exp.Length,
143        },
144        exp.DataType.Type.BOOLEAN: {
145            exp.Between,
146            exp.Boolean,
147            exp.In,
148            exp.RegexpLike,
149        },
150        exp.DataType.Type.DATE: {
151            exp.CurrentDate,
152            exp.Date,
153            exp.DateFromParts,
154            exp.DateStrToDate,
155            exp.DiToDate,
156            exp.StrToDate,
157            exp.TimeStrToDate,
158            exp.TsOrDsToDate,
159        },
160        exp.DataType.Type.DATETIME: {
161            exp.CurrentDatetime,
162            exp.DatetimeAdd,
163            exp.DatetimeSub,
164        },
165        exp.DataType.Type.DOUBLE: {
166            exp.ApproxQuantile,
167            exp.Avg,
168            exp.Div,
169            exp.Exp,
170            exp.Ln,
171            exp.Log,
172            exp.Log2,
173            exp.Log10,
174            exp.Pow,
175            exp.Quantile,
176            exp.Round,
177            exp.SafeDivide,
178            exp.Sqrt,
179            exp.Stddev,
180            exp.StddevPop,
181            exp.StddevSamp,
182            exp.Variance,
183            exp.VariancePop,
184        },
185        exp.DataType.Type.INT: {
186            exp.Ceil,
187            exp.DatetimeDiff,
188            exp.DateDiff,
189            exp.Extract,
190            exp.TimestampDiff,
191            exp.TimeDiff,
192            exp.DateToDi,
193            exp.Floor,
194            exp.Levenshtein,
195            exp.StrPosition,
196            exp.TsOrDiToDi,
197        },
198        exp.DataType.Type.TIMESTAMP: {
199            exp.CurrentTime,
200            exp.CurrentTimestamp,
201            exp.StrToTime,
202            exp.TimeAdd,
203            exp.TimeStrToTime,
204            exp.TimeSub,
205            exp.Timestamp,
206            exp.TimestampAdd,
207            exp.TimestampSub,
208            exp.UnixToTime,
209        },
210        exp.DataType.Type.TINYINT: {
211            exp.Day,
212            exp.Month,
213            exp.Week,
214            exp.Year,
215        },
216        exp.DataType.Type.VARCHAR: {
217            exp.ArrayConcat,
218            exp.Concat,
219            exp.ConcatWs,
220            exp.DateToDateStr,
221            exp.GroupConcat,
222            exp.Initcap,
223            exp.Lower,
224            exp.SafeConcat,
225            exp.SafeDPipe,
226            exp.Substring,
227            exp.TimeToStr,
228            exp.TimeToTimeStr,
229            exp.Trim,
230            exp.TsOrDsToDateStr,
231            exp.UnixToStr,
232            exp.UnixToTimeStr,
233            exp.Upper,
234        },
235    }
236
237    ANNOTATORS: t.Dict = {
238        **{
239            expr_type: lambda self, e: self._annotate_unary(e)
240            for expr_type in subclasses(exp.__name__, (exp.Unary, exp.Alias))
241        },
242        **{
243            expr_type: lambda self, e: self._annotate_binary(e)
244            for expr_type in subclasses(exp.__name__, exp.Binary)
245        },
246        **{
247            expr_type: _annotate_with_type_lambda(data_type)
248            for data_type, expressions in TYPE_TO_EXPRESSIONS.items()
249            for expr_type in expressions
250        },
251        exp.Abs: lambda self, e: self._annotate_by_args(e, "this"),
252        exp.Anonymous: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.UNKNOWN),
253        exp.Array: lambda self, e: self._annotate_by_args(e, "expressions", array=True),
254        exp.ArrayAgg: lambda self, e: self._annotate_by_args(e, "this", array=True),
255        exp.ArrayConcat: lambda self, e: self._annotate_by_args(e, "this", "expressions"),
256        exp.Bracket: lambda self, e: self._annotate_bracket(e),
257        exp.Cast: lambda self, e: self._annotate_with_type(e, e.args["to"]),
258        exp.Case: lambda self, e: self._annotate_by_args(e, "default", "ifs"),
259        exp.Coalesce: lambda self, e: self._annotate_by_args(e, "this", "expressions"),
260        exp.DataType: lambda self, e: self._annotate_with_type(e, e.copy()),
261        exp.DateAdd: lambda self, e: self._annotate_timeunit(e),
262        exp.DateSub: lambda self, e: self._annotate_timeunit(e),
263        exp.DateTrunc: lambda self, e: self._annotate_timeunit(e),
264        exp.Distinct: lambda self, e: self._annotate_by_args(e, "expressions"),
265        exp.Div: lambda self, e: self._annotate_div(e),
266        exp.Filter: lambda self, e: self._annotate_by_args(e, "this"),
267        exp.If: lambda self, e: self._annotate_by_args(e, "true", "false"),
268        exp.Interval: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.INTERVAL),
269        exp.Least: lambda self, e: self._annotate_by_args(e, "expressions"),
270        exp.Literal: lambda self, e: self._annotate_literal(e),
271        exp.Map: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.MAP),
272        exp.Max: lambda self, e: self._annotate_by_args(e, "this", "expressions"),
273        exp.Min: lambda self, e: self._annotate_by_args(e, "this", "expressions"),
274        exp.Null: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.NULL),
275        exp.Nullif: lambda self, e: self._annotate_by_args(e, "this", "expression"),
276        exp.Slice: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.UNKNOWN),
277        exp.Sum: lambda self, e: self._annotate_by_args(e, "this", "expressions", promote=True),
278        exp.TryCast: lambda self, e: self._annotate_with_type(e, e.args["to"]),
279        exp.VarMap: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.MAP),
280    }
281
282    NESTED_TYPES = {
283        exp.DataType.Type.ARRAY,
284    }
285
286    # Specifies what types a given type can be coerced into (autofilled)
287    COERCES_TO: t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]] = {}
288
289    # Coercion functions for binary operations.
290    # Map of type pairs to a callable that takes both sides of the binary operation and returns the resulting type.
291    BINARY_COERCIONS: BinaryCoercions = {
292        **swap_all(
293            {
294                (t, exp.DataType.Type.INTERVAL): lambda l, r: _coerce_date_literal(
295                    l, r.args.get("unit")
296                )
297                for t in exp.DataType.TEXT_TYPES
298            }
299        ),
300        **swap_all(
301            {
302                # text + numeric will yield the numeric type to match most dialects' semantics
303                (text, numeric): lambda l, r: t.cast(
304                    exp.DataType.Type, l.type if l.type in exp.DataType.NUMERIC_TYPES else r.type
305                )
306                for text in exp.DataType.TEXT_TYPES
307                for numeric in exp.DataType.NUMERIC_TYPES
308            }
309        ),
310        **swap_all(
311            {
312                (exp.DataType.Type.DATE, exp.DataType.Type.INTERVAL): lambda l, r: _coerce_date(
313                    l, r.args.get("unit")
314                ),
315            }
316        ),
317    }
318
319    def __init__(
320        self,
321        schema: Schema,
322        annotators: t.Optional[t.Dict[t.Type[E], t.Callable[[TypeAnnotator, E], E]]] = None,
323        coerces_to: t.Optional[t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]]] = None,
324        binary_coercions: t.Optional[BinaryCoercions] = None,
325    ) -> None:
326        self.schema = schema
327        self.annotators = annotators or self.ANNOTATORS
328        self.coerces_to = coerces_to or self.COERCES_TO
329        self.binary_coercions = binary_coercions or self.BINARY_COERCIONS
330
331        # Caches the ids of annotated sub-Expressions, to ensure we only visit them once
332        self._visited: t.Set[int] = set()
333
334    def _set_type(
335        self, expression: exp.Expression, target_type: exp.DataType | exp.DataType.Type
336    ) -> None:
337        expression.type = target_type  # type: ignore
338        self._visited.add(id(expression))
339
340    def annotate(self, expression: E) -> E:
341        for scope in traverse_scope(expression):
342            selects = {}
343            for name, source in scope.sources.items():
344                if not isinstance(source, Scope):
345                    continue
346                if isinstance(source.expression, exp.UDTF):
347                    values = []
348
349                    if isinstance(source.expression, exp.Lateral):
350                        if isinstance(source.expression.this, exp.Explode):
351                            values = [source.expression.this.this]
352                    else:
353                        values = source.expression.expressions[0].expressions
354
355                    if not values:
356                        continue
357
358                    selects[name] = {
359                        alias: column
360                        for alias, column in zip(
361                            source.expression.alias_column_names,
362                            values,
363                        )
364                    }
365                else:
366                    selects[name] = {
367                        select.alias_or_name: select for select in source.expression.selects
368                    }
369
370            # First annotate the current scope's column references
371            for col in scope.columns:
372                if not col.table:
373                    continue
374
375                source = scope.sources.get(col.table)
376                if isinstance(source, exp.Table):
377                    self._set_type(col, self.schema.get_column_type(source, col))
378                elif source and col.table in selects and col.name in selects[col.table]:
379                    self._set_type(col, selects[col.table][col.name].type)
380
381            # Then (possibly) annotate the remaining expressions in the scope
382            self._maybe_annotate(scope.expression)
383
384        return self._maybe_annotate(expression)  # This takes care of non-traversable expressions
385
386    def _maybe_annotate(self, expression: E) -> E:
387        if id(expression) in self._visited:
388            return expression  # We've already inferred the expression's type
389
390        annotator = self.annotators.get(expression.__class__)
391
392        return (
393            annotator(self, expression)
394            if annotator
395            else self._annotate_with_type(expression, exp.DataType.Type.UNKNOWN)
396        )
397
398    def _annotate_args(self, expression: E) -> E:
399        for _, value in expression.iter_expressions():
400            self._maybe_annotate(value)
401
402        return expression
403
404    def _maybe_coerce(
405        self, type1: exp.DataType | exp.DataType.Type, type2: exp.DataType | exp.DataType.Type
406    ) -> exp.DataType | exp.DataType.Type:
407        type1_value = type1.this if isinstance(type1, exp.DataType) else type1
408        type2_value = type2.this if isinstance(type2, exp.DataType) else type2
409
410        # We propagate the NULL / UNKNOWN types upwards if found
411        if exp.DataType.Type.NULL in (type1_value, type2_value):
412            return exp.DataType.Type.NULL
413        if exp.DataType.Type.UNKNOWN in (type1_value, type2_value):
414            return exp.DataType.Type.UNKNOWN
415
416        if type1_value in self.NESTED_TYPES:
417            return type1
418        if type2_value in self.NESTED_TYPES:
419            return type2
420
421        return type2_value if type2_value in self.coerces_to.get(type1_value, {}) else type1_value  # type: ignore
422
423    # Note: the following "no_type_check" decorators were added because mypy was yelling due
424    # to assigning Type values to expression.type (since its getter returns Optional[DataType]).
425    # This is a known mypy issue: https://github.com/python/mypy/issues/3004
426
427    @t.no_type_check
428    def _annotate_binary(self, expression: B) -> B:
429        self._annotate_args(expression)
430
431        left, right = expression.left, expression.right
432        left_type, right_type = left.type.this, right.type.this
433
434        if isinstance(expression, exp.Connector):
435            if left_type == exp.DataType.Type.NULL and right_type == exp.DataType.Type.NULL:
436                self._set_type(expression, exp.DataType.Type.NULL)
437            elif exp.DataType.Type.NULL in (left_type, right_type):
438                self._set_type(
439                    expression,
440                    exp.DataType.build("NULLABLE", expressions=exp.DataType.build("BOOLEAN")),
441                )
442            else:
443                self._set_type(expression, exp.DataType.Type.BOOLEAN)
444        elif isinstance(expression, exp.Predicate):
445            self._set_type(expression, exp.DataType.Type.BOOLEAN)
446        elif (left_type, right_type) in self.binary_coercions:
447            self._set_type(expression, self.binary_coercions[(left_type, right_type)](left, right))
448        else:
449            self._set_type(expression, self._maybe_coerce(left_type, right_type))
450
451        return expression
452
453    @t.no_type_check
454    def _annotate_unary(self, expression: E) -> E:
455        self._annotate_args(expression)
456
457        if isinstance(expression, exp.Condition) and not isinstance(expression, exp.Paren):
458            self._set_type(expression, exp.DataType.Type.BOOLEAN)
459        else:
460            self._set_type(expression, expression.this.type)
461
462        return expression
463
464    @t.no_type_check
465    def _annotate_literal(self, expression: exp.Literal) -> exp.Literal:
466        if expression.is_string:
467            self._set_type(expression, exp.DataType.Type.VARCHAR)
468        elif expression.is_int:
469            self._set_type(expression, exp.DataType.Type.INT)
470        else:
471            self._set_type(expression, exp.DataType.Type.DOUBLE)
472
473        return expression
474
475    @t.no_type_check
476    def _annotate_with_type(self, expression: E, target_type: exp.DataType.Type) -> E:
477        self._set_type(expression, target_type)
478        return self._annotate_args(expression)
479
480    @t.no_type_check
481    def _annotate_by_args(
482        self, expression: E, *args: str, promote: bool = False, array: bool = False
483    ) -> E:
484        self._annotate_args(expression)
485
486        expressions: t.List[exp.Expression] = []
487        for arg in args:
488            arg_expr = expression.args.get(arg)
489            expressions.extend(expr for expr in ensure_list(arg_expr) if expr)
490
491        last_datatype = None
492        for expr in expressions:
493            last_datatype = self._maybe_coerce(last_datatype or expr.type, expr.type)
494
495        self._set_type(expression, last_datatype or exp.DataType.Type.UNKNOWN)
496
497        if promote:
498            if expression.type.this in exp.DataType.INTEGER_TYPES:
499                self._set_type(expression, exp.DataType.Type.BIGINT)
500            elif expression.type.this in exp.DataType.FLOAT_TYPES:
501                self._set_type(expression, exp.DataType.Type.DOUBLE)
502
503        if array:
504            self._set_type(
505                expression,
506                exp.DataType(
507                    this=exp.DataType.Type.ARRAY, expressions=[expression.type], nested=True
508                ),
509            )
510
511        return expression
512
513    def _annotate_timeunit(
514        self, expression: exp.TimeUnit | exp.DateTrunc
515    ) -> exp.TimeUnit | exp.DateTrunc:
516        self._annotate_args(expression)
517
518        if expression.this.type.this in exp.DataType.TEXT_TYPES:
519            datatype = _coerce_date_literal(expression.this, expression.unit)
520        elif expression.this.type.this in exp.DataType.TEMPORAL_TYPES:
521            datatype = _coerce_date(expression.this, expression.unit)
522        else:
523            datatype = exp.DataType.Type.UNKNOWN
524
525        self._set_type(expression, datatype)
526        return expression
527
528    def _annotate_bracket(self, expression: exp.Bracket) -> exp.Bracket:
529        self._annotate_args(expression)
530
531        bracket_arg = expression.expressions[0]
532        this = expression.this
533
534        if isinstance(bracket_arg, exp.Slice):
535            self._set_type(expression, this.type)
536        elif this.type.is_type(exp.DataType.Type.ARRAY):
537            contained_type = seq_get(this.type.expressions, 0) or exp.DataType.Type.UNKNOWN
538            self._set_type(expression, contained_type)
539        elif isinstance(this, (exp.Map, exp.VarMap)) and bracket_arg in this.keys:
540            index = this.keys.index(bracket_arg)
541            value = seq_get(this.values, index)
542            value_type = value.type if value else exp.DataType.Type.UNKNOWN
543            self._set_type(expression, value_type or exp.DataType.Type.UNKNOWN)
544        else:
545            self._set_type(expression, exp.DataType.Type.UNKNOWN)
546
547        return expression
548
549    def _annotate_div(self, expression: exp.Div) -> exp.Div:
550        self._annotate_args(expression)
551
552        left_type, right_type = expression.left.type.this, expression.right.type.this  # type: ignore
553
554        if (
555            expression.args.get("typed")
556            and left_type in exp.DataType.INTEGER_TYPES
557            and right_type in exp.DataType.INTEGER_TYPES
558        ):
559            self._set_type(expression, exp.DataType.Type.BIGINT)
560        else:
561            self._set_type(expression, self._maybe_coerce(left_type, right_type))
562
563        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) -> ~E:
30def annotate_types(
31    expression: E,
32    schema: t.Optional[t.Dict | Schema] = None,
33    annotators: t.Optional[t.Dict[t.Type[E], t.Callable[[TypeAnnotator, E], E]]] = None,
34    coerces_to: t.Optional[t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]]] = None,
35) -> E:
36    """
37    Infers the types of an expression, annotating its AST accordingly.
38
39    Example:
40        >>> import sqlglot
41        >>> schema = {"y": {"cola": "SMALLINT"}}
42        >>> sql = "SELECT x.cola + 2.5 AS cola FROM (SELECT y.cola AS cola FROM y AS y) AS x"
43        >>> annotated_expr = annotate_types(sqlglot.parse_one(sql), schema=schema)
44        >>> annotated_expr.expressions[0].type.this  # Get the type of "x.cola + 2.5 AS cola"
45        <Type.DOUBLE: 'DOUBLE'>
46
47    Args:
48        expression: Expression to annotate.
49        schema: Database schema.
50        annotators: Maps expression type to corresponding annotation function.
51        coerces_to: Maps expression type to set of types that it can be coerced into.
52
53    Returns:
54        The expression annotated with types.
55    """
56
57    schema = ensure_schema(schema)
58
59    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.

86def swap_args(func: BinaryCoercionFunc) -> BinaryCoercionFunc:
87    @functools.wraps(func)
88    def _swapped(l: exp.Expression, r: exp.Expression) -> exp.DataType.Type:
89        return func(r, l)
90
91    return _swapped
94def swap_all(coercions: BinaryCoercions) -> BinaryCoercions:
95    return {**coercions, **{(b, a): swap_args(func) for (a, b), func in coercions.items()}}
class TypeAnnotator:
137class TypeAnnotator(metaclass=_TypeAnnotator):
138    TYPE_TO_EXPRESSIONS: t.Dict[exp.DataType.Type, t.Set[t.Type[exp.Expression]]] = {
139        exp.DataType.Type.BIGINT: {
140            exp.ApproxDistinct,
141            exp.ArraySize,
142            exp.Count,
143            exp.Length,
144        },
145        exp.DataType.Type.BOOLEAN: {
146            exp.Between,
147            exp.Boolean,
148            exp.In,
149            exp.RegexpLike,
150        },
151        exp.DataType.Type.DATE: {
152            exp.CurrentDate,
153            exp.Date,
154            exp.DateFromParts,
155            exp.DateStrToDate,
156            exp.DiToDate,
157            exp.StrToDate,
158            exp.TimeStrToDate,
159            exp.TsOrDsToDate,
160        },
161        exp.DataType.Type.DATETIME: {
162            exp.CurrentDatetime,
163            exp.DatetimeAdd,
164            exp.DatetimeSub,
165        },
166        exp.DataType.Type.DOUBLE: {
167            exp.ApproxQuantile,
168            exp.Avg,
169            exp.Div,
170            exp.Exp,
171            exp.Ln,
172            exp.Log,
173            exp.Log2,
174            exp.Log10,
175            exp.Pow,
176            exp.Quantile,
177            exp.Round,
178            exp.SafeDivide,
179            exp.Sqrt,
180            exp.Stddev,
181            exp.StddevPop,
182            exp.StddevSamp,
183            exp.Variance,
184            exp.VariancePop,
185        },
186        exp.DataType.Type.INT: {
187            exp.Ceil,
188            exp.DatetimeDiff,
189            exp.DateDiff,
190            exp.Extract,
191            exp.TimestampDiff,
192            exp.TimeDiff,
193            exp.DateToDi,
194            exp.Floor,
195            exp.Levenshtein,
196            exp.StrPosition,
197            exp.TsOrDiToDi,
198        },
199        exp.DataType.Type.TIMESTAMP: {
200            exp.CurrentTime,
201            exp.CurrentTimestamp,
202            exp.StrToTime,
203            exp.TimeAdd,
204            exp.TimeStrToTime,
205            exp.TimeSub,
206            exp.Timestamp,
207            exp.TimestampAdd,
208            exp.TimestampSub,
209            exp.UnixToTime,
210        },
211        exp.DataType.Type.TINYINT: {
212            exp.Day,
213            exp.Month,
214            exp.Week,
215            exp.Year,
216        },
217        exp.DataType.Type.VARCHAR: {
218            exp.ArrayConcat,
219            exp.Concat,
220            exp.ConcatWs,
221            exp.DateToDateStr,
222            exp.GroupConcat,
223            exp.Initcap,
224            exp.Lower,
225            exp.SafeConcat,
226            exp.SafeDPipe,
227            exp.Substring,
228            exp.TimeToStr,
229            exp.TimeToTimeStr,
230            exp.Trim,
231            exp.TsOrDsToDateStr,
232            exp.UnixToStr,
233            exp.UnixToTimeStr,
234            exp.Upper,
235        },
236    }
237
238    ANNOTATORS: t.Dict = {
239        **{
240            expr_type: lambda self, e: self._annotate_unary(e)
241            for expr_type in subclasses(exp.__name__, (exp.Unary, exp.Alias))
242        },
243        **{
244            expr_type: lambda self, e: self._annotate_binary(e)
245            for expr_type in subclasses(exp.__name__, exp.Binary)
246        },
247        **{
248            expr_type: _annotate_with_type_lambda(data_type)
249            for data_type, expressions in TYPE_TO_EXPRESSIONS.items()
250            for expr_type in expressions
251        },
252        exp.Abs: lambda self, e: self._annotate_by_args(e, "this"),
253        exp.Anonymous: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.UNKNOWN),
254        exp.Array: lambda self, e: self._annotate_by_args(e, "expressions", array=True),
255        exp.ArrayAgg: lambda self, e: self._annotate_by_args(e, "this", array=True),
256        exp.ArrayConcat: lambda self, e: self._annotate_by_args(e, "this", "expressions"),
257        exp.Bracket: lambda self, e: self._annotate_bracket(e),
258        exp.Cast: lambda self, e: self._annotate_with_type(e, e.args["to"]),
259        exp.Case: lambda self, e: self._annotate_by_args(e, "default", "ifs"),
260        exp.Coalesce: lambda self, e: self._annotate_by_args(e, "this", "expressions"),
261        exp.DataType: lambda self, e: self._annotate_with_type(e, e.copy()),
262        exp.DateAdd: lambda self, e: self._annotate_timeunit(e),
263        exp.DateSub: lambda self, e: self._annotate_timeunit(e),
264        exp.DateTrunc: lambda self, e: self._annotate_timeunit(e),
265        exp.Distinct: lambda self, e: self._annotate_by_args(e, "expressions"),
266        exp.Div: lambda self, e: self._annotate_div(e),
267        exp.Filter: lambda self, e: self._annotate_by_args(e, "this"),
268        exp.If: lambda self, e: self._annotate_by_args(e, "true", "false"),
269        exp.Interval: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.INTERVAL),
270        exp.Least: lambda self, e: self._annotate_by_args(e, "expressions"),
271        exp.Literal: lambda self, e: self._annotate_literal(e),
272        exp.Map: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.MAP),
273        exp.Max: lambda self, e: self._annotate_by_args(e, "this", "expressions"),
274        exp.Min: lambda self, e: self._annotate_by_args(e, "this", "expressions"),
275        exp.Null: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.NULL),
276        exp.Nullif: lambda self, e: self._annotate_by_args(e, "this", "expression"),
277        exp.Slice: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.UNKNOWN),
278        exp.Sum: lambda self, e: self._annotate_by_args(e, "this", "expressions", promote=True),
279        exp.TryCast: lambda self, e: self._annotate_with_type(e, e.args["to"]),
280        exp.VarMap: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.MAP),
281    }
282
283    NESTED_TYPES = {
284        exp.DataType.Type.ARRAY,
285    }
286
287    # Specifies what types a given type can be coerced into (autofilled)
288    COERCES_TO: t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]] = {}
289
290    # Coercion functions for binary operations.
291    # Map of type pairs to a callable that takes both sides of the binary operation and returns the resulting type.
292    BINARY_COERCIONS: BinaryCoercions = {
293        **swap_all(
294            {
295                (t, exp.DataType.Type.INTERVAL): lambda l, r: _coerce_date_literal(
296                    l, r.args.get("unit")
297                )
298                for t in exp.DataType.TEXT_TYPES
299            }
300        ),
301        **swap_all(
302            {
303                # text + numeric will yield the numeric type to match most dialects' semantics
304                (text, numeric): lambda l, r: t.cast(
305                    exp.DataType.Type, l.type if l.type in exp.DataType.NUMERIC_TYPES else r.type
306                )
307                for text in exp.DataType.TEXT_TYPES
308                for numeric in exp.DataType.NUMERIC_TYPES
309            }
310        ),
311        **swap_all(
312            {
313                (exp.DataType.Type.DATE, exp.DataType.Type.INTERVAL): lambda l, r: _coerce_date(
314                    l, r.args.get("unit")
315                ),
316            }
317        ),
318    }
319
320    def __init__(
321        self,
322        schema: Schema,
323        annotators: t.Optional[t.Dict[t.Type[E], t.Callable[[TypeAnnotator, E], E]]] = None,
324        coerces_to: t.Optional[t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]]] = None,
325        binary_coercions: t.Optional[BinaryCoercions] = None,
326    ) -> None:
327        self.schema = schema
328        self.annotators = annotators or self.ANNOTATORS
329        self.coerces_to = coerces_to or self.COERCES_TO
330        self.binary_coercions = binary_coercions or self.BINARY_COERCIONS
331
332        # Caches the ids of annotated sub-Expressions, to ensure we only visit them once
333        self._visited: t.Set[int] = set()
334
335    def _set_type(
336        self, expression: exp.Expression, target_type: exp.DataType | exp.DataType.Type
337    ) -> None:
338        expression.type = target_type  # type: ignore
339        self._visited.add(id(expression))
340
341    def annotate(self, expression: E) -> E:
342        for scope in traverse_scope(expression):
343            selects = {}
344            for name, source in scope.sources.items():
345                if not isinstance(source, Scope):
346                    continue
347                if isinstance(source.expression, exp.UDTF):
348                    values = []
349
350                    if isinstance(source.expression, exp.Lateral):
351                        if isinstance(source.expression.this, exp.Explode):
352                            values = [source.expression.this.this]
353                    else:
354                        values = source.expression.expressions[0].expressions
355
356                    if not values:
357                        continue
358
359                    selects[name] = {
360                        alias: column
361                        for alias, column in zip(
362                            source.expression.alias_column_names,
363                            values,
364                        )
365                    }
366                else:
367                    selects[name] = {
368                        select.alias_or_name: select for select in source.expression.selects
369                    }
370
371            # First annotate the current scope's column references
372            for col in scope.columns:
373                if not col.table:
374                    continue
375
376                source = scope.sources.get(col.table)
377                if isinstance(source, exp.Table):
378                    self._set_type(col, self.schema.get_column_type(source, col))
379                elif source and col.table in selects and col.name in selects[col.table]:
380                    self._set_type(col, selects[col.table][col.name].type)
381
382            # Then (possibly) annotate the remaining expressions in the scope
383            self._maybe_annotate(scope.expression)
384
385        return self._maybe_annotate(expression)  # This takes care of non-traversable expressions
386
387    def _maybe_annotate(self, expression: E) -> E:
388        if id(expression) in self._visited:
389            return expression  # We've already inferred the expression's type
390
391        annotator = self.annotators.get(expression.__class__)
392
393        return (
394            annotator(self, expression)
395            if annotator
396            else self._annotate_with_type(expression, exp.DataType.Type.UNKNOWN)
397        )
398
399    def _annotate_args(self, expression: E) -> E:
400        for _, value in expression.iter_expressions():
401            self._maybe_annotate(value)
402
403        return expression
404
405    def _maybe_coerce(
406        self, type1: exp.DataType | exp.DataType.Type, type2: exp.DataType | exp.DataType.Type
407    ) -> exp.DataType | exp.DataType.Type:
408        type1_value = type1.this if isinstance(type1, exp.DataType) else type1
409        type2_value = type2.this if isinstance(type2, exp.DataType) else type2
410
411        # We propagate the NULL / UNKNOWN types upwards if found
412        if exp.DataType.Type.NULL in (type1_value, type2_value):
413            return exp.DataType.Type.NULL
414        if exp.DataType.Type.UNKNOWN in (type1_value, type2_value):
415            return exp.DataType.Type.UNKNOWN
416
417        if type1_value in self.NESTED_TYPES:
418            return type1
419        if type2_value in self.NESTED_TYPES:
420            return type2
421
422        return type2_value if type2_value in self.coerces_to.get(type1_value, {}) else type1_value  # type: ignore
423
424    # Note: the following "no_type_check" decorators were added because mypy was yelling due
425    # to assigning Type values to expression.type (since its getter returns Optional[DataType]).
426    # This is a known mypy issue: https://github.com/python/mypy/issues/3004
427
428    @t.no_type_check
429    def _annotate_binary(self, expression: B) -> B:
430        self._annotate_args(expression)
431
432        left, right = expression.left, expression.right
433        left_type, right_type = left.type.this, right.type.this
434
435        if isinstance(expression, exp.Connector):
436            if left_type == exp.DataType.Type.NULL and right_type == exp.DataType.Type.NULL:
437                self._set_type(expression, exp.DataType.Type.NULL)
438            elif exp.DataType.Type.NULL in (left_type, right_type):
439                self._set_type(
440                    expression,
441                    exp.DataType.build("NULLABLE", expressions=exp.DataType.build("BOOLEAN")),
442                )
443            else:
444                self._set_type(expression, exp.DataType.Type.BOOLEAN)
445        elif isinstance(expression, exp.Predicate):
446            self._set_type(expression, exp.DataType.Type.BOOLEAN)
447        elif (left_type, right_type) in self.binary_coercions:
448            self._set_type(expression, self.binary_coercions[(left_type, right_type)](left, right))
449        else:
450            self._set_type(expression, self._maybe_coerce(left_type, right_type))
451
452        return expression
453
454    @t.no_type_check
455    def _annotate_unary(self, expression: E) -> E:
456        self._annotate_args(expression)
457
458        if isinstance(expression, exp.Condition) and not isinstance(expression, exp.Paren):
459            self._set_type(expression, exp.DataType.Type.BOOLEAN)
460        else:
461            self._set_type(expression, expression.this.type)
462
463        return expression
464
465    @t.no_type_check
466    def _annotate_literal(self, expression: exp.Literal) -> exp.Literal:
467        if expression.is_string:
468            self._set_type(expression, exp.DataType.Type.VARCHAR)
469        elif expression.is_int:
470            self._set_type(expression, exp.DataType.Type.INT)
471        else:
472            self._set_type(expression, exp.DataType.Type.DOUBLE)
473
474        return expression
475
476    @t.no_type_check
477    def _annotate_with_type(self, expression: E, target_type: exp.DataType.Type) -> E:
478        self._set_type(expression, target_type)
479        return self._annotate_args(expression)
480
481    @t.no_type_check
482    def _annotate_by_args(
483        self, expression: E, *args: str, promote: bool = False, array: bool = False
484    ) -> E:
485        self._annotate_args(expression)
486
487        expressions: t.List[exp.Expression] = []
488        for arg in args:
489            arg_expr = expression.args.get(arg)
490            expressions.extend(expr for expr in ensure_list(arg_expr) if expr)
491
492        last_datatype = None
493        for expr in expressions:
494            last_datatype = self._maybe_coerce(last_datatype or expr.type, expr.type)
495
496        self._set_type(expression, last_datatype or exp.DataType.Type.UNKNOWN)
497
498        if promote:
499            if expression.type.this in exp.DataType.INTEGER_TYPES:
500                self._set_type(expression, exp.DataType.Type.BIGINT)
501            elif expression.type.this in exp.DataType.FLOAT_TYPES:
502                self._set_type(expression, exp.DataType.Type.DOUBLE)
503
504        if array:
505            self._set_type(
506                expression,
507                exp.DataType(
508                    this=exp.DataType.Type.ARRAY, expressions=[expression.type], nested=True
509                ),
510            )
511
512        return expression
513
514    def _annotate_timeunit(
515        self, expression: exp.TimeUnit | exp.DateTrunc
516    ) -> exp.TimeUnit | exp.DateTrunc:
517        self._annotate_args(expression)
518
519        if expression.this.type.this in exp.DataType.TEXT_TYPES:
520            datatype = _coerce_date_literal(expression.this, expression.unit)
521        elif expression.this.type.this in exp.DataType.TEMPORAL_TYPES:
522            datatype = _coerce_date(expression.this, expression.unit)
523        else:
524            datatype = exp.DataType.Type.UNKNOWN
525
526        self._set_type(expression, datatype)
527        return expression
528
529    def _annotate_bracket(self, expression: exp.Bracket) -> exp.Bracket:
530        self._annotate_args(expression)
531
532        bracket_arg = expression.expressions[0]
533        this = expression.this
534
535        if isinstance(bracket_arg, exp.Slice):
536            self._set_type(expression, this.type)
537        elif this.type.is_type(exp.DataType.Type.ARRAY):
538            contained_type = seq_get(this.type.expressions, 0) or exp.DataType.Type.UNKNOWN
539            self._set_type(expression, contained_type)
540        elif isinstance(this, (exp.Map, exp.VarMap)) and bracket_arg in this.keys:
541            index = this.keys.index(bracket_arg)
542            value = seq_get(this.values, index)
543            value_type = value.type if value else exp.DataType.Type.UNKNOWN
544            self._set_type(expression, value_type or exp.DataType.Type.UNKNOWN)
545        else:
546            self._set_type(expression, exp.DataType.Type.UNKNOWN)
547
548        return expression
549
550    def _annotate_div(self, expression: exp.Div) -> exp.Div:
551        self._annotate_args(expression)
552
553        left_type, right_type = expression.left.type.this, expression.right.type.this  # type: ignore
554
555        if (
556            expression.args.get("typed")
557            and left_type in exp.DataType.INTEGER_TYPES
558            and right_type in exp.DataType.INTEGER_TYPES
559        ):
560            self._set_type(expression, exp.DataType.Type.BIGINT)
561        else:
562            self._set_type(expression, self._maybe_coerce(left_type, right_type))
563
564        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)
320    def __init__(
321        self,
322        schema: Schema,
323        annotators: t.Optional[t.Dict[t.Type[E], t.Callable[[TypeAnnotator, E], E]]] = None,
324        coerces_to: t.Optional[t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]]] = None,
325        binary_coercions: t.Optional[BinaryCoercions] = None,
326    ) -> None:
327        self.schema = schema
328        self.annotators = annotators or self.ANNOTATORS
329        self.coerces_to = coerces_to or self.COERCES_TO
330        self.binary_coercions = binary_coercions or self.BINARY_COERCIONS
331
332        # Caches the ids of annotated sub-Expressions, to ensure we only visit them once
333        self._visited: t.Set[int] = set()
TYPE_TO_EXPRESSIONS: Dict[sqlglot.expressions.DataType.Type, Set[Type[sqlglot.expressions.Expression]]] = {<Type.BIGINT: 'BIGINT'>: {<class 'sqlglot.expressions.Count'>, <class 'sqlglot.expressions.ArraySize'>, <class 'sqlglot.expressions.ApproxDistinct'>, <class 'sqlglot.expressions.Length'>}, <Type.BOOLEAN: 'BOOLEAN'>: {<class 'sqlglot.expressions.Between'>, <class 'sqlglot.expressions.In'>, <class 'sqlglot.expressions.RegexpLike'>, <class 'sqlglot.expressions.Boolean'>}, <Type.DATE: 'DATE'>: {<class 'sqlglot.expressions.DateFromParts'>, <class 'sqlglot.expressions.TsOrDsToDate'>, <class 'sqlglot.expressions.DiToDate'>, <class 'sqlglot.expressions.CurrentDate'>, <class 'sqlglot.expressions.Date'>, <class 'sqlglot.expressions.TimeStrToDate'>, <class 'sqlglot.expressions.StrToDate'>, <class 'sqlglot.expressions.DateStrToDate'>}, <Type.DATETIME: 'DATETIME'>: {<class 'sqlglot.expressions.DatetimeAdd'>, <class 'sqlglot.expressions.CurrentDatetime'>, <class 'sqlglot.expressions.DatetimeSub'>}, <Type.DOUBLE: 'DOUBLE'>: {<class 'sqlglot.expressions.VariancePop'>, <class 'sqlglot.expressions.Avg'>, <class 'sqlglot.expressions.Log10'>, <class 'sqlglot.expressions.Div'>, <class 'sqlglot.expressions.Pow'>, <class 'sqlglot.expressions.Variance'>, <class 'sqlglot.expressions.Log2'>, <class 'sqlglot.expressions.Log'>, <class 'sqlglot.expressions.Round'>, <class 'sqlglot.expressions.StddevSamp'>, <class 'sqlglot.expressions.Ln'>, <class 'sqlglot.expressions.StddevPop'>, <class 'sqlglot.expressions.ApproxQuantile'>, <class 'sqlglot.expressions.Stddev'>, <class 'sqlglot.expressions.Sqrt'>, <class 'sqlglot.expressions.Quantile'>, <class 'sqlglot.expressions.Exp'>, <class 'sqlglot.expressions.SafeDivide'>}, <Type.INT: 'INT'>: {<class 'sqlglot.expressions.Floor'>, <class 'sqlglot.expressions.Extract'>, <class 'sqlglot.expressions.Ceil'>, <class 'sqlglot.expressions.TimeDiff'>, <class 'sqlglot.expressions.DateDiff'>, <class 'sqlglot.expressions.DateToDi'>, <class 'sqlglot.expressions.Levenshtein'>, <class 'sqlglot.expressions.TimestampDiff'>, <class 'sqlglot.expressions.TsOrDiToDi'>, <class 'sqlglot.expressions.DatetimeDiff'>, <class 'sqlglot.expressions.StrPosition'>}, <Type.TIMESTAMP: 'TIMESTAMP'>: {<class 'sqlglot.expressions.TimestampAdd'>, <class 'sqlglot.expressions.CurrentTime'>, <class 'sqlglot.expressions.Timestamp'>, <class 'sqlglot.expressions.TimeSub'>, <class 'sqlglot.expressions.TimeAdd'>, <class 'sqlglot.expressions.UnixToTime'>, <class 'sqlglot.expressions.StrToTime'>, <class 'sqlglot.expressions.TimeStrToTime'>, <class 'sqlglot.expressions.TimestampSub'>, <class 'sqlglot.expressions.CurrentTimestamp'>}, <Type.TINYINT: 'TINYINT'>: {<class 'sqlglot.expressions.Month'>, <class 'sqlglot.expressions.Year'>, <class 'sqlglot.expressions.Day'>, <class 'sqlglot.expressions.Week'>}, <Type.VARCHAR: 'VARCHAR'>: {<class 'sqlglot.expressions.TimeToTimeStr'>, <class 'sqlglot.expressions.TsOrDsToDateStr'>, <class 'sqlglot.expressions.TimeToStr'>, <class 'sqlglot.expressions.Upper'>, <class 'sqlglot.expressions.Substring'>, <class 'sqlglot.expressions.UnixToTimeStr'>, <class 'sqlglot.expressions.ArrayConcat'>, <class 'sqlglot.expressions.Trim'>, <class 'sqlglot.expressions.GroupConcat'>, <class 'sqlglot.expressions.UnixToStr'>, <class 'sqlglot.expressions.ConcatWs'>, <class 'sqlglot.expressions.Lower'>, <class 'sqlglot.expressions.SafeDPipe'>, <class 'sqlglot.expressions.DateToDateStr'>, <class 'sqlglot.expressions.SafeConcat'>, <class 'sqlglot.expressions.Concat'>, <class 'sqlglot.expressions.Initcap'>}}
ANNOTATORS: Dict = {<class 'sqlglot.expressions.Alias'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.BitwiseNot'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Neg'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Not'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Paren'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Unary'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Add'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.And'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.ArrayContained'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.ArrayContains'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.ArrayOverlaps'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Binary'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.BitwiseAnd'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.BitwiseLeftShift'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.BitwiseOr'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.BitwiseRightShift'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.BitwiseXor'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Collate'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Connector'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.DPipe'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Distance'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Div'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.Dot'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.EQ'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Escape'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.GT'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.GTE'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Glob'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.ILike'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.ILikeAny'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.IntDiv'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Is'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.JSONArrayContains'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.JSONBContains'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.JSONBExtract'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.JSONBExtractScalar'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.JSONExtract'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.JSONExtractScalar'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Kwarg'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.LT'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.LTE'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Like'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.LikeAny'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Mod'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Mul'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.NEQ'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.NullSafeEQ'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.NullSafeNEQ'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Operator'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Or'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Overlaps'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Pow'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.PropertyEQ'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.RegexpILike'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.RegexpLike'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.SafeDPipe'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.SimilarTo'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Slice'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.Sub'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Xor'>: <function TypeAnnotator.<dictcomp>.<lambda>>, <class 'sqlglot.expressions.Count'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.ArraySize'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.ApproxDistinct'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Length'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Between'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.In'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Boolean'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.DateFromParts'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TsOrDsToDate'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.DiToDate'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.CurrentDate'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Date'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TimeStrToDate'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.StrToDate'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.DateStrToDate'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.DatetimeAdd'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.CurrentDatetime'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.DatetimeSub'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.VariancePop'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Avg'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Log10'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Variance'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Log2'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Log'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Round'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.StddevSamp'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Ln'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.StddevPop'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.ApproxQuantile'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Stddev'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Sqrt'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Quantile'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Exp'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.SafeDivide'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Floor'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Extract'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Ceil'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TimeDiff'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.DateDiff'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.DateToDi'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Levenshtein'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TimestampDiff'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TsOrDiToDi'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.DatetimeDiff'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.StrPosition'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TimestampAdd'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.CurrentTime'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Timestamp'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TimeSub'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TimeAdd'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.UnixToTime'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.StrToTime'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TimeStrToTime'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TimestampSub'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.CurrentTimestamp'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Month'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Year'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Day'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Week'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TimeToTimeStr'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TsOrDsToDateStr'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.TimeToStr'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Upper'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Substring'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.UnixToTimeStr'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.ArrayConcat'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.Trim'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.GroupConcat'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.UnixToStr'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.ConcatWs'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Lower'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.DateToDateStr'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.SafeConcat'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Concat'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Initcap'>: <function _annotate_with_type_lambda.<locals>.<lambda>>, <class 'sqlglot.expressions.Abs'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.Anonymous'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.Array'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.ArrayAgg'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.Bracket'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.Cast'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.Case'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.Coalesce'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.DataType'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.DateAdd'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.DateSub'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.DateTrunc'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.Distinct'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.Filter'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.If'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.Interval'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.Least'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.Literal'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.Map'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.Max'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.Min'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.Null'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.Nullif'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.Sum'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.TryCast'>: <function TypeAnnotator.<lambda>>, <class 'sqlglot.expressions.VarMap'>: <function TypeAnnotator.<lambda>>}
NESTED_TYPES = {<Type.ARRAY: 'ARRAY'>}
COERCES_TO: Dict[sqlglot.expressions.DataType.Type, Set[sqlglot.expressions.DataType.Type]] = {<Type.TEXT: 'TEXT'>: set(), <Type.NVARCHAR: 'NVARCHAR'>: {<Type.TEXT: 'TEXT'>}, <Type.VARCHAR: 'VARCHAR'>: {<Type.TEXT: 'TEXT'>, <Type.NVARCHAR: 'NVARCHAR'>}, <Type.NCHAR: 'NCHAR'>: {<Type.TEXT: 'TEXT'>, <Type.VARCHAR: 'VARCHAR'>, <Type.NVARCHAR: 'NVARCHAR'>}, <Type.CHAR: 'CHAR'>: {<Type.TEXT: 'TEXT'>, <Type.VARCHAR: 'VARCHAR'>, <Type.NVARCHAR: 'NVARCHAR'>, <Type.NCHAR: 'NCHAR'>}, <Type.DOUBLE: 'DOUBLE'>: set(), <Type.FLOAT: 'FLOAT'>: {<Type.DOUBLE: 'DOUBLE'>}, <Type.DECIMAL: 'DECIMAL'>: {<Type.FLOAT: 'FLOAT'>, <Type.DOUBLE: 'DOUBLE'>}, <Type.BIGINT: 'BIGINT'>: {<Type.DECIMAL: 'DECIMAL'>, <Type.FLOAT: 'FLOAT'>, <Type.DOUBLE: 'DOUBLE'>}, <Type.INT: 'INT'>: {<Type.DECIMAL: 'DECIMAL'>, <Type.BIGINT: 'BIGINT'>, <Type.FLOAT: 'FLOAT'>, <Type.DOUBLE: 'DOUBLE'>}, <Type.SMALLINT: 'SMALLINT'>: {<Type.DECIMAL: 'DECIMAL'>, <Type.BIGINT: 'BIGINT'>, <Type.DOUBLE: 'DOUBLE'>, <Type.FLOAT: 'FLOAT'>, <Type.INT: 'INT'>}, <Type.TINYINT: 'TINYINT'>: {<Type.DECIMAL: 'DECIMAL'>, <Type.BIGINT: 'BIGINT'>, <Type.SMALLINT: 'SMALLINT'>, <Type.DOUBLE: 'DOUBLE'>, <Type.FLOAT: 'FLOAT'>, <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.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <Type.TIMESTAMP: 'TIMESTAMP'>}, <Type.DATE: 'DATE'>: {<Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <Type.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <Type.TIMESTAMP: 'TIMESTAMP'>, <Type.DATETIME: 'DATETIME'>}}
BINARY_COERCIONS: Dict[Tuple[sqlglot.expressions.DataType.Type, sqlglot.expressions.DataType.Type], Callable[[sqlglot.expressions.Expression, sqlglot.expressions.Expression], sqlglot.expressions.DataType.Type]] = {(<Type.NCHAR: 'NCHAR'>, <Type.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.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.INTERVAL: 'INTERVAL'>, <Type.NCHAR: 'NCHAR'>): <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.NCHAR: 'NCHAR'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DATE: 'DATE'>, <Type.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<lambda>>, (<Type.INTERVAL: 'INTERVAL'>, <Type.DATE: 'DATE'>): <function TypeAnnotator.<lambda>>}
schema
annotators
coerces_to
binary_coercions
def annotate(self, expression: ~E) -> ~E:
341    def annotate(self, expression: E) -> E:
342        for scope in traverse_scope(expression):
343            selects = {}
344            for name, source in scope.sources.items():
345                if not isinstance(source, Scope):
346                    continue
347                if isinstance(source.expression, exp.UDTF):
348                    values = []
349
350                    if isinstance(source.expression, exp.Lateral):
351                        if isinstance(source.expression.this, exp.Explode):
352                            values = [source.expression.this.this]
353                    else:
354                        values = source.expression.expressions[0].expressions
355
356                    if not values:
357                        continue
358
359                    selects[name] = {
360                        alias: column
361                        for alias, column in zip(
362                            source.expression.alias_column_names,
363                            values,
364                        )
365                    }
366                else:
367                    selects[name] = {
368                        select.alias_or_name: select for select in source.expression.selects
369                    }
370
371            # First annotate the current scope's column references
372            for col in scope.columns:
373                if not col.table:
374                    continue
375
376                source = scope.sources.get(col.table)
377                if isinstance(source, exp.Table):
378                    self._set_type(col, self.schema.get_column_type(source, col))
379                elif source and col.table in selects and col.name in selects[col.table]:
380                    self._set_type(col, selects[col.table][col.name].type)
381
382            # Then (possibly) annotate the remaining expressions in the scope
383            self._maybe_annotate(scope.expression)
384
385        return self._maybe_annotate(expression)  # This takes care of non-traversable expressions