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.
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]:
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]]:
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>>}
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>>}
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