sqlglot.optimizer.annotate_types
1from __future__ import annotations 2 3import functools 4import typing as t 5 6from sqlglot import exp 7from sqlglot.helper import ( 8 ensure_list, 9 is_date_unit, 10 is_iso_date, 11 is_iso_datetime, 12 seq_get, 13) 14from sqlglot.optimizer.scope import Scope, traverse_scope 15from sqlglot.schema import MappingSchema, Schema, ensure_schema 16from sqlglot.dialects.dialect import Dialect 17 18if t.TYPE_CHECKING: 19 from sqlglot._typing import B, E 20 21 BinaryCoercionFunc = t.Callable[[exp.Expression, exp.Expression], exp.DataType.Type] 22 BinaryCoercions = t.Dict[ 23 t.Tuple[exp.DataType.Type, exp.DataType.Type], 24 BinaryCoercionFunc, 25 ] 26 27 from sqlglot.dialects.dialect import DialectType, AnnotatorsType 28 29 30def annotate_types( 31 expression: E, 32 schema: t.Optional[t.Dict | Schema] = None, 33 annotators: t.Optional[AnnotatorsType] = None, 34 coerces_to: t.Optional[t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]]] = None, 35 dialect: DialectType = None, 36) -> E: 37 """ 38 Infers the types of an expression, annotating its AST accordingly. 39 40 Example: 41 >>> import sqlglot 42 >>> schema = {"y": {"cola": "SMALLINT"}} 43 >>> sql = "SELECT x.cola + 2.5 AS cola FROM (SELECT y.cola AS cola FROM y AS y) AS x" 44 >>> annotated_expr = annotate_types(sqlglot.parse_one(sql), schema=schema) 45 >>> annotated_expr.expressions[0].type.this # Get the type of "x.cola + 2.5 AS cola" 46 <Type.DOUBLE: 'DOUBLE'> 47 48 Args: 49 expression: Expression to annotate. 50 schema: Database schema. 51 annotators: Maps expression type to corresponding annotation function. 52 coerces_to: Maps expression type to set of types that it can be coerced into. 53 54 Returns: 55 The expression annotated with types. 56 """ 57 58 schema = ensure_schema(schema, dialect=dialect) 59 60 return TypeAnnotator(schema, annotators, coerces_to).annotate(expression) 61 62 63def _coerce_date_literal(l: exp.Expression, unit: t.Optional[exp.Expression]) -> exp.DataType.Type: 64 date_text = l.name 65 is_iso_date_ = is_iso_date(date_text) 66 67 if is_iso_date_ and is_date_unit(unit): 68 return exp.DataType.Type.DATE 69 70 # An ISO date is also an ISO datetime, but not vice versa 71 if is_iso_date_ or is_iso_datetime(date_text): 72 return exp.DataType.Type.DATETIME 73 74 return exp.DataType.Type.UNKNOWN 75 76 77def _coerce_date(l: exp.Expression, unit: t.Optional[exp.Expression]) -> exp.DataType.Type: 78 if not is_date_unit(unit): 79 return exp.DataType.Type.DATETIME 80 return l.type.this if l.type else exp.DataType.Type.UNKNOWN 81 82 83def swap_args(func: BinaryCoercionFunc) -> BinaryCoercionFunc: 84 @functools.wraps(func) 85 def _swapped(l: exp.Expression, r: exp.Expression) -> exp.DataType.Type: 86 return func(r, l) 87 88 return _swapped 89 90 91def swap_all(coercions: BinaryCoercions) -> BinaryCoercions: 92 return {**coercions, **{(b, a): swap_args(func) for (a, b), func in coercions.items()}} 93 94 95class _TypeAnnotator(type): 96 def __new__(cls, clsname, bases, attrs): 97 klass = super().__new__(cls, clsname, bases, attrs) 98 99 # Highest-to-lowest type precedence, as specified in Spark's docs (ANSI): 100 # https://spark.apache.org/docs/3.2.0/sql-ref-ansi-compliance.html 101 text_precedence = ( 102 exp.DataType.Type.TEXT, 103 exp.DataType.Type.NVARCHAR, 104 exp.DataType.Type.VARCHAR, 105 exp.DataType.Type.NCHAR, 106 exp.DataType.Type.CHAR, 107 ) 108 numeric_precedence = ( 109 exp.DataType.Type.DOUBLE, 110 exp.DataType.Type.FLOAT, 111 exp.DataType.Type.DECIMAL, 112 exp.DataType.Type.BIGINT, 113 exp.DataType.Type.INT, 114 exp.DataType.Type.SMALLINT, 115 exp.DataType.Type.TINYINT, 116 ) 117 timelike_precedence = ( 118 exp.DataType.Type.TIMESTAMPLTZ, 119 exp.DataType.Type.TIMESTAMPTZ, 120 exp.DataType.Type.TIMESTAMP, 121 exp.DataType.Type.DATETIME, 122 exp.DataType.Type.DATE, 123 ) 124 125 for type_precedence in (text_precedence, numeric_precedence, timelike_precedence): 126 coerces_to = set() 127 for data_type in type_precedence: 128 klass.COERCES_TO[data_type] = coerces_to.copy() 129 coerces_to |= {data_type} 130 131 # NULL can be coerced to any type, so e.g. NULL + 1 will have type INT 132 klass.COERCES_TO[exp.DataType.Type.NULL] = { 133 *text_precedence, 134 *numeric_precedence, 135 *timelike_precedence, 136 } 137 138 return klass 139 140 141class TypeAnnotator(metaclass=_TypeAnnotator): 142 NESTED_TYPES = { 143 exp.DataType.Type.ARRAY, 144 } 145 146 # Specifies what types a given type can be coerced into (autofilled) 147 COERCES_TO: t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]] = {} 148 149 # Coercion functions for binary operations. 150 # Map of type pairs to a callable that takes both sides of the binary operation and returns the resulting type. 151 BINARY_COERCIONS: BinaryCoercions = { 152 **swap_all( 153 { 154 (t, exp.DataType.Type.INTERVAL): lambda l, r: _coerce_date_literal( 155 l, r.args.get("unit") 156 ) 157 for t in exp.DataType.TEXT_TYPES 158 } 159 ), 160 **swap_all( 161 { 162 # text + numeric will yield the numeric type to match most dialects' semantics 163 (text, numeric): lambda l, r: t.cast( 164 exp.DataType.Type, l.type if l.type in exp.DataType.NUMERIC_TYPES else r.type 165 ) 166 for text in exp.DataType.TEXT_TYPES 167 for numeric in exp.DataType.NUMERIC_TYPES 168 } 169 ), 170 **swap_all( 171 { 172 (exp.DataType.Type.DATE, exp.DataType.Type.INTERVAL): lambda l, r: _coerce_date( 173 l, r.args.get("unit") 174 ), 175 } 176 ), 177 } 178 179 def __init__( 180 self, 181 schema: Schema, 182 annotators: t.Optional[AnnotatorsType] = None, 183 coerces_to: t.Optional[t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]]] = None, 184 binary_coercions: t.Optional[BinaryCoercions] = None, 185 ) -> None: 186 self.schema = schema 187 self.annotators = annotators or Dialect.get_or_raise(schema.dialect).ANNOTATORS 188 self.coerces_to = ( 189 coerces_to or Dialect.get_or_raise(schema.dialect).COERCES_TO or self.COERCES_TO 190 ) 191 self.binary_coercions = binary_coercions or self.BINARY_COERCIONS 192 193 # Caches the ids of annotated sub-Expressions, to ensure we only visit them once 194 self._visited: t.Set[int] = set() 195 196 # Maps an exp.SetOperation's id (e.g. UNION) to its projection types. This is computed if the 197 # exp.SetOperation is the expression of a scope source, as selecting from it multiple times 198 # would reprocess the entire subtree to coerce the types of its operands' projections 199 self._setop_column_types: t.Dict[int, t.Dict[str, exp.DataType | exp.DataType.Type]] = {} 200 201 def _set_type( 202 self, expression: exp.Expression, target_type: t.Optional[exp.DataType | exp.DataType.Type] 203 ) -> None: 204 expression.type = target_type or exp.DataType.Type.UNKNOWN # type: ignore 205 self._visited.add(id(expression)) 206 207 def annotate(self, expression: E) -> E: 208 for scope in traverse_scope(expression): 209 self.annotate_scope(scope) 210 return self._maybe_annotate(expression) # This takes care of non-traversable expressions 211 212 def annotate_scope(self, scope: Scope) -> None: 213 selects = {} 214 for name, source in scope.sources.items(): 215 if not isinstance(source, Scope): 216 continue 217 218 expression = source.expression 219 if isinstance(expression, exp.UDTF): 220 values = [] 221 222 if isinstance(expression, exp.Lateral): 223 if isinstance(expression.this, exp.Explode): 224 values = [expression.this.this] 225 elif isinstance(expression, exp.Unnest): 226 values = [expression] 227 elif not isinstance(expression, exp.TableFromRows): 228 values = expression.expressions[0].expressions 229 230 if not values: 231 continue 232 233 selects[name] = { 234 alias: column.type 235 for alias, column in zip(expression.alias_column_names, values) 236 } 237 elif isinstance(expression, exp.SetOperation) and len(expression.left.selects) == len( 238 expression.right.selects 239 ): 240 selects[name] = col_types = self._setop_column_types.setdefault(id(expression), {}) 241 242 if not col_types: 243 # Process a chain / sub-tree of set operations 244 for set_op in expression.walk( 245 prune=lambda n: not isinstance(n, (exp.SetOperation, exp.Subquery)) 246 ): 247 if not isinstance(set_op, exp.SetOperation): 248 continue 249 250 if set_op.args.get("by_name"): 251 r_type_by_select = { 252 s.alias_or_name: s.type for s in set_op.right.selects 253 } 254 setop_cols = { 255 s.alias_or_name: self._maybe_coerce( 256 t.cast(exp.DataType, s.type), 257 r_type_by_select.get(s.alias_or_name) 258 or exp.DataType.Type.UNKNOWN, 259 ) 260 for s in set_op.left.selects 261 } 262 else: 263 setop_cols = { 264 ls.alias_or_name: self._maybe_coerce( 265 t.cast(exp.DataType, ls.type), t.cast(exp.DataType, rs.type) 266 ) 267 for ls, rs in zip(set_op.left.selects, set_op.right.selects) 268 } 269 270 # Coerce intermediate results with the previously registered types, if they exist 271 for col_name, col_type in setop_cols.items(): 272 col_types[col_name] = self._maybe_coerce( 273 col_type, col_types.get(col_name, exp.DataType.Type.NULL) 274 ) 275 276 else: 277 selects[name] = {s.alias_or_name: s.type for s in expression.selects} 278 279 # First annotate the current scope's column references 280 for col in scope.columns: 281 if not col.table: 282 continue 283 284 source = scope.sources.get(col.table) 285 if isinstance(source, exp.Table): 286 self._set_type(col, self.schema.get_column_type(source, col)) 287 elif source: 288 if col.table in selects and col.name in selects[col.table]: 289 self._set_type(col, selects[col.table][col.name]) 290 elif isinstance(source.expression, exp.Unnest): 291 self._set_type(col, source.expression.type) 292 293 if isinstance(self.schema, MappingSchema): 294 for table_column in scope.table_columns: 295 source = scope.sources.get(table_column.name) 296 297 if isinstance(source, exp.Table): 298 schema = self.schema.find( 299 source, raise_on_missing=False, ensure_data_types=True 300 ) 301 if not isinstance(schema, dict): 302 continue 303 304 struct_type = exp.DataType( 305 this=exp.DataType.Type.STRUCT, 306 expressions=[ 307 exp.ColumnDef(this=exp.to_identifier(c), kind=kind) 308 for c, kind in schema.items() 309 ], 310 nested=True, 311 ) 312 self._set_type(table_column, struct_type) 313 elif ( 314 isinstance(source, Scope) 315 and isinstance(source.expression, exp.Query) 316 and ( 317 source.expression.meta.get("query_type") or exp.DataType.build("UNKNOWN") 318 ).is_type(exp.DataType.Type.STRUCT) 319 ): 320 self._set_type(table_column, source.expression.meta["query_type"]) 321 322 # Then (possibly) annotate the remaining expressions in the scope 323 self._maybe_annotate(scope.expression) 324 325 if self.schema.dialect == "bigquery" and isinstance(scope.expression, exp.Query): 326 struct_type = exp.DataType( 327 this=exp.DataType.Type.STRUCT, 328 expressions=[ 329 exp.ColumnDef( 330 this=exp.to_identifier(select.output_name), 331 kind=select.type.copy() if select.type else None, 332 ) 333 for select in scope.expression.selects 334 ], 335 nested=True, 336 ) 337 338 if not any( 339 cd.kind.is_type(exp.DataType.Type.UNKNOWN) 340 for cd in struct_type.expressions 341 if cd.kind 342 ): 343 # We don't use `_set_type` on purpose here. If we annotated the query directly, then 344 # using it in other contexts (e.g., ARRAY(<query>)) could result in incorrect type 345 # annotations, i.e., it shouldn't be interpreted as a STRUCT value. 346 scope.expression.meta["query_type"] = struct_type 347 348 def _maybe_annotate(self, expression: E) -> E: 349 if id(expression) in self._visited: 350 return expression # We've already inferred the expression's type 351 352 annotator = self.annotators.get(expression.__class__) 353 354 return ( 355 annotator(self, expression) 356 if annotator 357 else self._annotate_with_type(expression, exp.DataType.Type.UNKNOWN) 358 ) 359 360 def _annotate_args(self, expression: E) -> E: 361 for value in expression.iter_expressions(): 362 self._maybe_annotate(value) 363 364 return expression 365 366 def _maybe_coerce( 367 self, 368 type1: exp.DataType | exp.DataType.Type, 369 type2: exp.DataType | exp.DataType.Type, 370 ) -> exp.DataType | exp.DataType.Type: 371 """ 372 Returns type2 if type1 can be coerced into it, otherwise type1. 373 374 If either type is parameterized (e.g. DECIMAL(18, 2) contains two parameters), 375 we assume type1 does not coerce into type2, so we also return it in this case. 376 """ 377 if isinstance(type1, exp.DataType): 378 if type1.expressions: 379 return type1 380 type1_value = type1.this 381 else: 382 type1_value = type1 383 384 if isinstance(type2, exp.DataType): 385 if type2.expressions: 386 return type2 387 type2_value = type2.this 388 else: 389 type2_value = type2 390 391 # We propagate the UNKNOWN type upwards if found 392 if exp.DataType.Type.UNKNOWN in (type1_value, type2_value): 393 return exp.DataType.Type.UNKNOWN 394 395 return type2_value if type2_value in self.coerces_to.get(type1_value, {}) else type1_value 396 397 def _annotate_binary(self, expression: B) -> B: 398 self._annotate_args(expression) 399 400 left, right = expression.left, expression.right 401 left_type, right_type = left.type.this, right.type.this # type: ignore 402 403 if isinstance(expression, (exp.Connector, exp.Predicate)): 404 self._set_type(expression, exp.DataType.Type.BOOLEAN) 405 elif (left_type, right_type) in self.binary_coercions: 406 self._set_type(expression, self.binary_coercions[(left_type, right_type)](left, right)) 407 else: 408 self._set_type(expression, self._maybe_coerce(left_type, right_type)) 409 410 return expression 411 412 def _annotate_unary(self, expression: E) -> E: 413 self._annotate_args(expression) 414 415 if isinstance(expression, exp.Not): 416 self._set_type(expression, exp.DataType.Type.BOOLEAN) 417 else: 418 self._set_type(expression, expression.this.type) 419 420 return expression 421 422 def _annotate_literal(self, expression: exp.Literal) -> exp.Literal: 423 if expression.is_string: 424 self._set_type(expression, exp.DataType.Type.VARCHAR) 425 elif expression.is_int: 426 self._set_type(expression, exp.DataType.Type.INT) 427 else: 428 self._set_type(expression, exp.DataType.Type.DOUBLE) 429 430 return expression 431 432 def _annotate_with_type( 433 self, expression: E, target_type: exp.DataType | exp.DataType.Type 434 ) -> E: 435 self._set_type(expression, target_type) 436 return self._annotate_args(expression) 437 438 @t.no_type_check 439 def _annotate_by_args( 440 self, 441 expression: E, 442 *args: str, 443 promote: bool = False, 444 array: bool = False, 445 ) -> E: 446 self._annotate_args(expression) 447 448 expressions: t.List[exp.Expression] = [] 449 for arg in args: 450 arg_expr = expression.args.get(arg) 451 expressions.extend(expr for expr in ensure_list(arg_expr) if expr) 452 453 last_datatype = None 454 for expr in expressions: 455 expr_type = expr.type 456 457 # Stop at the first nested data type found - we don't want to _maybe_coerce nested types 458 if expr_type.args.get("nested"): 459 last_datatype = expr_type 460 break 461 462 if not expr_type.is_type(exp.DataType.Type.UNKNOWN): 463 last_datatype = self._maybe_coerce(last_datatype or expr_type, expr_type) 464 465 self._set_type(expression, last_datatype or exp.DataType.Type.UNKNOWN) 466 467 if promote: 468 if expression.type.this in exp.DataType.INTEGER_TYPES: 469 self._set_type(expression, exp.DataType.Type.BIGINT) 470 elif expression.type.this in exp.DataType.FLOAT_TYPES: 471 self._set_type(expression, exp.DataType.Type.DOUBLE) 472 473 if array: 474 self._set_type( 475 expression, 476 exp.DataType( 477 this=exp.DataType.Type.ARRAY, expressions=[expression.type], nested=True 478 ), 479 ) 480 481 return expression 482 483 def _annotate_timeunit( 484 self, expression: exp.TimeUnit | exp.DateTrunc 485 ) -> exp.TimeUnit | exp.DateTrunc: 486 self._annotate_args(expression) 487 488 if expression.this.type.this in exp.DataType.TEXT_TYPES: 489 datatype = _coerce_date_literal(expression.this, expression.unit) 490 elif expression.this.type.this in exp.DataType.TEMPORAL_TYPES: 491 datatype = _coerce_date(expression.this, expression.unit) 492 else: 493 datatype = exp.DataType.Type.UNKNOWN 494 495 self._set_type(expression, datatype) 496 return expression 497 498 def _annotate_bracket(self, expression: exp.Bracket) -> exp.Bracket: 499 self._annotate_args(expression) 500 501 bracket_arg = expression.expressions[0] 502 this = expression.this 503 504 if isinstance(bracket_arg, exp.Slice): 505 self._set_type(expression, this.type) 506 elif this.type.is_type(exp.DataType.Type.ARRAY): 507 self._set_type(expression, seq_get(this.type.expressions, 0)) 508 elif isinstance(this, (exp.Map, exp.VarMap)) and bracket_arg in this.keys: 509 index = this.keys.index(bracket_arg) 510 value = seq_get(this.values, index) 511 self._set_type(expression, value.type if value else None) 512 else: 513 self._set_type(expression, exp.DataType.Type.UNKNOWN) 514 515 return expression 516 517 def _annotate_div(self, expression: exp.Div) -> exp.Div: 518 self._annotate_args(expression) 519 520 left_type, right_type = expression.left.type.this, expression.right.type.this # type: ignore 521 522 if ( 523 expression.args.get("typed") 524 and left_type in exp.DataType.INTEGER_TYPES 525 and right_type in exp.DataType.INTEGER_TYPES 526 ): 527 self._set_type(expression, exp.DataType.Type.BIGINT) 528 else: 529 self._set_type(expression, self._maybe_coerce(left_type, right_type)) 530 if expression.type and expression.type.this not in exp.DataType.REAL_TYPES: 531 self._set_type( 532 expression, self._maybe_coerce(expression.type, exp.DataType.Type.DOUBLE) 533 ) 534 535 return expression 536 537 def _annotate_dot(self, expression: exp.Dot) -> exp.Dot: 538 self._annotate_args(expression) 539 self._set_type(expression, None) 540 this_type = expression.this.type 541 542 if this_type and this_type.is_type(exp.DataType.Type.STRUCT): 543 for e in this_type.expressions: 544 if e.name == expression.expression.name: 545 self._set_type(expression, e.kind) 546 break 547 548 return expression 549 550 def _annotate_explode(self, expression: exp.Explode) -> exp.Explode: 551 self._annotate_args(expression) 552 self._set_type(expression, seq_get(expression.this.type.expressions, 0)) 553 return expression 554 555 def _annotate_unnest(self, expression: exp.Unnest) -> exp.Unnest: 556 self._annotate_args(expression) 557 child = seq_get(expression.expressions, 0) 558 559 if child and child.is_type(exp.DataType.Type.ARRAY): 560 expr_type = seq_get(child.type.expressions, 0) 561 else: 562 expr_type = None 563 564 self._set_type(expression, expr_type) 565 return expression 566 567 def _annotate_struct_value( 568 self, expression: exp.Expression 569 ) -> t.Optional[exp.DataType] | exp.ColumnDef: 570 alias = expression.args.get("alias") 571 if alias: 572 return exp.ColumnDef(this=alias.copy(), kind=expression.type) 573 574 # Case: key = value or key := value 575 if expression.expression: 576 return exp.ColumnDef(this=expression.this.copy(), kind=expression.expression.type) 577 578 return expression.type 579 580 def _annotate_struct(self, expression: exp.Struct) -> exp.Struct: 581 self._annotate_args(expression) 582 self._set_type( 583 expression, 584 exp.DataType( 585 this=exp.DataType.Type.STRUCT, 586 expressions=[self._annotate_struct_value(expr) for expr in expression.expressions], 587 nested=True, 588 ), 589 ) 590 return expression 591 592 @t.overload 593 def _annotate_map(self, expression: exp.Map) -> exp.Map: ... 594 595 @t.overload 596 def _annotate_map(self, expression: exp.VarMap) -> exp.VarMap: ... 597 598 def _annotate_map(self, expression): 599 self._annotate_args(expression) 600 601 keys = expression.args.get("keys") 602 values = expression.args.get("values") 603 604 map_type = exp.DataType(this=exp.DataType.Type.MAP) 605 if isinstance(keys, exp.Array) and isinstance(values, exp.Array): 606 key_type = seq_get(keys.type.expressions, 0) or exp.DataType.Type.UNKNOWN 607 value_type = seq_get(values.type.expressions, 0) or exp.DataType.Type.UNKNOWN 608 609 if key_type != exp.DataType.Type.UNKNOWN and value_type != exp.DataType.Type.UNKNOWN: 610 map_type.set("expressions", [key_type, value_type]) 611 map_type.set("nested", True) 612 613 self._set_type(expression, map_type) 614 return expression 615 616 def _annotate_to_map(self, expression: exp.ToMap) -> exp.ToMap: 617 self._annotate_args(expression) 618 619 map_type = exp.DataType(this=exp.DataType.Type.MAP) 620 arg = expression.this 621 if arg.is_type(exp.DataType.Type.STRUCT): 622 for coldef in arg.type.expressions: 623 kind = coldef.kind 624 if kind != exp.DataType.Type.UNKNOWN: 625 map_type.set("expressions", [exp.DataType.build("varchar"), kind]) 626 map_type.set("nested", True) 627 break 628 629 self._set_type(expression, map_type) 630 return expression 631 632 def _annotate_extract(self, expression: exp.Extract) -> exp.Extract: 633 self._annotate_args(expression) 634 part = expression.name 635 if part == "TIME": 636 self._set_type(expression, exp.DataType.Type.TIME) 637 elif part == "DATE": 638 self._set_type(expression, exp.DataType.Type.DATE) 639 else: 640 self._set_type(expression, exp.DataType.Type.INT) 641 return expression 642 643 def _annotate_by_array_element(self, expression: exp.Expression) -> exp.Expression: 644 self._annotate_args(expression) 645 646 array_arg = expression.this 647 if array_arg.type.is_type(exp.DataType.Type.ARRAY): 648 element_type = seq_get(array_arg.type.expressions, 0) or exp.DataType.Type.UNKNOWN 649 self._set_type(expression, element_type) 650 else: 651 self._set_type(expression, exp.DataType.Type.UNKNOWN) 652 653 return expression
def
annotate_types( expression: ~E, schema: Union[Dict, sqlglot.schema.Schema, NoneType] = None, annotators: Optional[Dict[Type[~E], Callable[[TypeAnnotator, ~E], ~E]]] = None, coerces_to: Optional[Dict[sqlglot.expressions.DataType.Type, Set[sqlglot.expressions.DataType.Type]]] = None, dialect: Union[str, sqlglot.dialects.Dialect, Type[sqlglot.dialects.Dialect], NoneType] = None) -> ~E:
31def annotate_types( 32 expression: E, 33 schema: t.Optional[t.Dict | Schema] = None, 34 annotators: t.Optional[AnnotatorsType] = None, 35 coerces_to: t.Optional[t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]]] = None, 36 dialect: DialectType = None, 37) -> E: 38 """ 39 Infers the types of an expression, annotating its AST accordingly. 40 41 Example: 42 >>> import sqlglot 43 >>> schema = {"y": {"cola": "SMALLINT"}} 44 >>> sql = "SELECT x.cola + 2.5 AS cola FROM (SELECT y.cola AS cola FROM y AS y) AS x" 45 >>> annotated_expr = annotate_types(sqlglot.parse_one(sql), schema=schema) 46 >>> annotated_expr.expressions[0].type.this # Get the type of "x.cola + 2.5 AS cola" 47 <Type.DOUBLE: 'DOUBLE'> 48 49 Args: 50 expression: Expression to annotate. 51 schema: Database schema. 52 annotators: Maps expression type to corresponding annotation function. 53 coerces_to: Maps expression type to set of types that it can be coerced into. 54 55 Returns: 56 The expression annotated with types. 57 """ 58 59 schema = ensure_schema(schema, dialect=dialect) 60 61 return TypeAnnotator(schema, annotators, coerces_to).annotate(expression)
Infers the types of an expression, annotating its AST accordingly.
Example:
>>> import sqlglot >>> schema = {"y": {"cola": "SMALLINT"}} >>> sql = "SELECT x.cola + 2.5 AS cola FROM (SELECT y.cola AS cola FROM y AS y) AS x" >>> annotated_expr = annotate_types(sqlglot.parse_one(sql), schema=schema) >>> annotated_expr.expressions[0].type.this # Get the type of "x.cola + 2.5 AS cola" <Type.DOUBLE: 'DOUBLE'>
Arguments:
- expression: Expression to annotate.
- schema: Database schema.
- annotators: Maps expression type to corresponding annotation function.
- coerces_to: Maps expression type to set of types that it can be coerced into.
Returns:
The expression annotated with types.
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:
142class TypeAnnotator(metaclass=_TypeAnnotator): 143 NESTED_TYPES = { 144 exp.DataType.Type.ARRAY, 145 } 146 147 # Specifies what types a given type can be coerced into (autofilled) 148 COERCES_TO: t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]] = {} 149 150 # Coercion functions for binary operations. 151 # Map of type pairs to a callable that takes both sides of the binary operation and returns the resulting type. 152 BINARY_COERCIONS: BinaryCoercions = { 153 **swap_all( 154 { 155 (t, exp.DataType.Type.INTERVAL): lambda l, r: _coerce_date_literal( 156 l, r.args.get("unit") 157 ) 158 for t in exp.DataType.TEXT_TYPES 159 } 160 ), 161 **swap_all( 162 { 163 # text + numeric will yield the numeric type to match most dialects' semantics 164 (text, numeric): lambda l, r: t.cast( 165 exp.DataType.Type, l.type if l.type in exp.DataType.NUMERIC_TYPES else r.type 166 ) 167 for text in exp.DataType.TEXT_TYPES 168 for numeric in exp.DataType.NUMERIC_TYPES 169 } 170 ), 171 **swap_all( 172 { 173 (exp.DataType.Type.DATE, exp.DataType.Type.INTERVAL): lambda l, r: _coerce_date( 174 l, r.args.get("unit") 175 ), 176 } 177 ), 178 } 179 180 def __init__( 181 self, 182 schema: Schema, 183 annotators: t.Optional[AnnotatorsType] = None, 184 coerces_to: t.Optional[t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]]] = None, 185 binary_coercions: t.Optional[BinaryCoercions] = None, 186 ) -> None: 187 self.schema = schema 188 self.annotators = annotators or Dialect.get_or_raise(schema.dialect).ANNOTATORS 189 self.coerces_to = ( 190 coerces_to or Dialect.get_or_raise(schema.dialect).COERCES_TO or self.COERCES_TO 191 ) 192 self.binary_coercions = binary_coercions or self.BINARY_COERCIONS 193 194 # Caches the ids of annotated sub-Expressions, to ensure we only visit them once 195 self._visited: t.Set[int] = set() 196 197 # Maps an exp.SetOperation's id (e.g. UNION) to its projection types. This is computed if the 198 # exp.SetOperation is the expression of a scope source, as selecting from it multiple times 199 # would reprocess the entire subtree to coerce the types of its operands' projections 200 self._setop_column_types: t.Dict[int, t.Dict[str, exp.DataType | exp.DataType.Type]] = {} 201 202 def _set_type( 203 self, expression: exp.Expression, target_type: t.Optional[exp.DataType | exp.DataType.Type] 204 ) -> None: 205 expression.type = target_type or exp.DataType.Type.UNKNOWN # type: ignore 206 self._visited.add(id(expression)) 207 208 def annotate(self, expression: E) -> E: 209 for scope in traverse_scope(expression): 210 self.annotate_scope(scope) 211 return self._maybe_annotate(expression) # This takes care of non-traversable expressions 212 213 def annotate_scope(self, scope: Scope) -> None: 214 selects = {} 215 for name, source in scope.sources.items(): 216 if not isinstance(source, Scope): 217 continue 218 219 expression = source.expression 220 if isinstance(expression, exp.UDTF): 221 values = [] 222 223 if isinstance(expression, exp.Lateral): 224 if isinstance(expression.this, exp.Explode): 225 values = [expression.this.this] 226 elif isinstance(expression, exp.Unnest): 227 values = [expression] 228 elif not isinstance(expression, exp.TableFromRows): 229 values = expression.expressions[0].expressions 230 231 if not values: 232 continue 233 234 selects[name] = { 235 alias: column.type 236 for alias, column in zip(expression.alias_column_names, values) 237 } 238 elif isinstance(expression, exp.SetOperation) and len(expression.left.selects) == len( 239 expression.right.selects 240 ): 241 selects[name] = col_types = self._setop_column_types.setdefault(id(expression), {}) 242 243 if not col_types: 244 # Process a chain / sub-tree of set operations 245 for set_op in expression.walk( 246 prune=lambda n: not isinstance(n, (exp.SetOperation, exp.Subquery)) 247 ): 248 if not isinstance(set_op, exp.SetOperation): 249 continue 250 251 if set_op.args.get("by_name"): 252 r_type_by_select = { 253 s.alias_or_name: s.type for s in set_op.right.selects 254 } 255 setop_cols = { 256 s.alias_or_name: self._maybe_coerce( 257 t.cast(exp.DataType, s.type), 258 r_type_by_select.get(s.alias_or_name) 259 or exp.DataType.Type.UNKNOWN, 260 ) 261 for s in set_op.left.selects 262 } 263 else: 264 setop_cols = { 265 ls.alias_or_name: self._maybe_coerce( 266 t.cast(exp.DataType, ls.type), t.cast(exp.DataType, rs.type) 267 ) 268 for ls, rs in zip(set_op.left.selects, set_op.right.selects) 269 } 270 271 # Coerce intermediate results with the previously registered types, if they exist 272 for col_name, col_type in setop_cols.items(): 273 col_types[col_name] = self._maybe_coerce( 274 col_type, col_types.get(col_name, exp.DataType.Type.NULL) 275 ) 276 277 else: 278 selects[name] = {s.alias_or_name: s.type for s in expression.selects} 279 280 # First annotate the current scope's column references 281 for col in scope.columns: 282 if not col.table: 283 continue 284 285 source = scope.sources.get(col.table) 286 if isinstance(source, exp.Table): 287 self._set_type(col, self.schema.get_column_type(source, col)) 288 elif source: 289 if col.table in selects and col.name in selects[col.table]: 290 self._set_type(col, selects[col.table][col.name]) 291 elif isinstance(source.expression, exp.Unnest): 292 self._set_type(col, source.expression.type) 293 294 if isinstance(self.schema, MappingSchema): 295 for table_column in scope.table_columns: 296 source = scope.sources.get(table_column.name) 297 298 if isinstance(source, exp.Table): 299 schema = self.schema.find( 300 source, raise_on_missing=False, ensure_data_types=True 301 ) 302 if not isinstance(schema, dict): 303 continue 304 305 struct_type = exp.DataType( 306 this=exp.DataType.Type.STRUCT, 307 expressions=[ 308 exp.ColumnDef(this=exp.to_identifier(c), kind=kind) 309 for c, kind in schema.items() 310 ], 311 nested=True, 312 ) 313 self._set_type(table_column, struct_type) 314 elif ( 315 isinstance(source, Scope) 316 and isinstance(source.expression, exp.Query) 317 and ( 318 source.expression.meta.get("query_type") or exp.DataType.build("UNKNOWN") 319 ).is_type(exp.DataType.Type.STRUCT) 320 ): 321 self._set_type(table_column, source.expression.meta["query_type"]) 322 323 # Then (possibly) annotate the remaining expressions in the scope 324 self._maybe_annotate(scope.expression) 325 326 if self.schema.dialect == "bigquery" and isinstance(scope.expression, exp.Query): 327 struct_type = exp.DataType( 328 this=exp.DataType.Type.STRUCT, 329 expressions=[ 330 exp.ColumnDef( 331 this=exp.to_identifier(select.output_name), 332 kind=select.type.copy() if select.type else None, 333 ) 334 for select in scope.expression.selects 335 ], 336 nested=True, 337 ) 338 339 if not any( 340 cd.kind.is_type(exp.DataType.Type.UNKNOWN) 341 for cd in struct_type.expressions 342 if cd.kind 343 ): 344 # We don't use `_set_type` on purpose here. If we annotated the query directly, then 345 # using it in other contexts (e.g., ARRAY(<query>)) could result in incorrect type 346 # annotations, i.e., it shouldn't be interpreted as a STRUCT value. 347 scope.expression.meta["query_type"] = struct_type 348 349 def _maybe_annotate(self, expression: E) -> E: 350 if id(expression) in self._visited: 351 return expression # We've already inferred the expression's type 352 353 annotator = self.annotators.get(expression.__class__) 354 355 return ( 356 annotator(self, expression) 357 if annotator 358 else self._annotate_with_type(expression, exp.DataType.Type.UNKNOWN) 359 ) 360 361 def _annotate_args(self, expression: E) -> E: 362 for value in expression.iter_expressions(): 363 self._maybe_annotate(value) 364 365 return expression 366 367 def _maybe_coerce( 368 self, 369 type1: exp.DataType | exp.DataType.Type, 370 type2: exp.DataType | exp.DataType.Type, 371 ) -> exp.DataType | exp.DataType.Type: 372 """ 373 Returns type2 if type1 can be coerced into it, otherwise type1. 374 375 If either type is parameterized (e.g. DECIMAL(18, 2) contains two parameters), 376 we assume type1 does not coerce into type2, so we also return it in this case. 377 """ 378 if isinstance(type1, exp.DataType): 379 if type1.expressions: 380 return type1 381 type1_value = type1.this 382 else: 383 type1_value = type1 384 385 if isinstance(type2, exp.DataType): 386 if type2.expressions: 387 return type2 388 type2_value = type2.this 389 else: 390 type2_value = type2 391 392 # We propagate the UNKNOWN type upwards if found 393 if exp.DataType.Type.UNKNOWN in (type1_value, type2_value): 394 return exp.DataType.Type.UNKNOWN 395 396 return type2_value if type2_value in self.coerces_to.get(type1_value, {}) else type1_value 397 398 def _annotate_binary(self, expression: B) -> B: 399 self._annotate_args(expression) 400 401 left, right = expression.left, expression.right 402 left_type, right_type = left.type.this, right.type.this # type: ignore 403 404 if isinstance(expression, (exp.Connector, exp.Predicate)): 405 self._set_type(expression, exp.DataType.Type.BOOLEAN) 406 elif (left_type, right_type) in self.binary_coercions: 407 self._set_type(expression, self.binary_coercions[(left_type, right_type)](left, right)) 408 else: 409 self._set_type(expression, self._maybe_coerce(left_type, right_type)) 410 411 return expression 412 413 def _annotate_unary(self, expression: E) -> E: 414 self._annotate_args(expression) 415 416 if isinstance(expression, exp.Not): 417 self._set_type(expression, exp.DataType.Type.BOOLEAN) 418 else: 419 self._set_type(expression, expression.this.type) 420 421 return expression 422 423 def _annotate_literal(self, expression: exp.Literal) -> exp.Literal: 424 if expression.is_string: 425 self._set_type(expression, exp.DataType.Type.VARCHAR) 426 elif expression.is_int: 427 self._set_type(expression, exp.DataType.Type.INT) 428 else: 429 self._set_type(expression, exp.DataType.Type.DOUBLE) 430 431 return expression 432 433 def _annotate_with_type( 434 self, expression: E, target_type: exp.DataType | exp.DataType.Type 435 ) -> E: 436 self._set_type(expression, target_type) 437 return self._annotate_args(expression) 438 439 @t.no_type_check 440 def _annotate_by_args( 441 self, 442 expression: E, 443 *args: str, 444 promote: bool = False, 445 array: bool = False, 446 ) -> E: 447 self._annotate_args(expression) 448 449 expressions: t.List[exp.Expression] = [] 450 for arg in args: 451 arg_expr = expression.args.get(arg) 452 expressions.extend(expr for expr in ensure_list(arg_expr) if expr) 453 454 last_datatype = None 455 for expr in expressions: 456 expr_type = expr.type 457 458 # Stop at the first nested data type found - we don't want to _maybe_coerce nested types 459 if expr_type.args.get("nested"): 460 last_datatype = expr_type 461 break 462 463 if not expr_type.is_type(exp.DataType.Type.UNKNOWN): 464 last_datatype = self._maybe_coerce(last_datatype or expr_type, expr_type) 465 466 self._set_type(expression, last_datatype or exp.DataType.Type.UNKNOWN) 467 468 if promote: 469 if expression.type.this in exp.DataType.INTEGER_TYPES: 470 self._set_type(expression, exp.DataType.Type.BIGINT) 471 elif expression.type.this in exp.DataType.FLOAT_TYPES: 472 self._set_type(expression, exp.DataType.Type.DOUBLE) 473 474 if array: 475 self._set_type( 476 expression, 477 exp.DataType( 478 this=exp.DataType.Type.ARRAY, expressions=[expression.type], nested=True 479 ), 480 ) 481 482 return expression 483 484 def _annotate_timeunit( 485 self, expression: exp.TimeUnit | exp.DateTrunc 486 ) -> exp.TimeUnit | exp.DateTrunc: 487 self._annotate_args(expression) 488 489 if expression.this.type.this in exp.DataType.TEXT_TYPES: 490 datatype = _coerce_date_literal(expression.this, expression.unit) 491 elif expression.this.type.this in exp.DataType.TEMPORAL_TYPES: 492 datatype = _coerce_date(expression.this, expression.unit) 493 else: 494 datatype = exp.DataType.Type.UNKNOWN 495 496 self._set_type(expression, datatype) 497 return expression 498 499 def _annotate_bracket(self, expression: exp.Bracket) -> exp.Bracket: 500 self._annotate_args(expression) 501 502 bracket_arg = expression.expressions[0] 503 this = expression.this 504 505 if isinstance(bracket_arg, exp.Slice): 506 self._set_type(expression, this.type) 507 elif this.type.is_type(exp.DataType.Type.ARRAY): 508 self._set_type(expression, seq_get(this.type.expressions, 0)) 509 elif isinstance(this, (exp.Map, exp.VarMap)) and bracket_arg in this.keys: 510 index = this.keys.index(bracket_arg) 511 value = seq_get(this.values, index) 512 self._set_type(expression, value.type if value else None) 513 else: 514 self._set_type(expression, exp.DataType.Type.UNKNOWN) 515 516 return expression 517 518 def _annotate_div(self, expression: exp.Div) -> exp.Div: 519 self._annotate_args(expression) 520 521 left_type, right_type = expression.left.type.this, expression.right.type.this # type: ignore 522 523 if ( 524 expression.args.get("typed") 525 and left_type in exp.DataType.INTEGER_TYPES 526 and right_type in exp.DataType.INTEGER_TYPES 527 ): 528 self._set_type(expression, exp.DataType.Type.BIGINT) 529 else: 530 self._set_type(expression, self._maybe_coerce(left_type, right_type)) 531 if expression.type and expression.type.this not in exp.DataType.REAL_TYPES: 532 self._set_type( 533 expression, self._maybe_coerce(expression.type, exp.DataType.Type.DOUBLE) 534 ) 535 536 return expression 537 538 def _annotate_dot(self, expression: exp.Dot) -> exp.Dot: 539 self._annotate_args(expression) 540 self._set_type(expression, None) 541 this_type = expression.this.type 542 543 if this_type and this_type.is_type(exp.DataType.Type.STRUCT): 544 for e in this_type.expressions: 545 if e.name == expression.expression.name: 546 self._set_type(expression, e.kind) 547 break 548 549 return expression 550 551 def _annotate_explode(self, expression: exp.Explode) -> exp.Explode: 552 self._annotate_args(expression) 553 self._set_type(expression, seq_get(expression.this.type.expressions, 0)) 554 return expression 555 556 def _annotate_unnest(self, expression: exp.Unnest) -> exp.Unnest: 557 self._annotate_args(expression) 558 child = seq_get(expression.expressions, 0) 559 560 if child and child.is_type(exp.DataType.Type.ARRAY): 561 expr_type = seq_get(child.type.expressions, 0) 562 else: 563 expr_type = None 564 565 self._set_type(expression, expr_type) 566 return expression 567 568 def _annotate_struct_value( 569 self, expression: exp.Expression 570 ) -> t.Optional[exp.DataType] | exp.ColumnDef: 571 alias = expression.args.get("alias") 572 if alias: 573 return exp.ColumnDef(this=alias.copy(), kind=expression.type) 574 575 # Case: key = value or key := value 576 if expression.expression: 577 return exp.ColumnDef(this=expression.this.copy(), kind=expression.expression.type) 578 579 return expression.type 580 581 def _annotate_struct(self, expression: exp.Struct) -> exp.Struct: 582 self._annotate_args(expression) 583 self._set_type( 584 expression, 585 exp.DataType( 586 this=exp.DataType.Type.STRUCT, 587 expressions=[self._annotate_struct_value(expr) for expr in expression.expressions], 588 nested=True, 589 ), 590 ) 591 return expression 592 593 @t.overload 594 def _annotate_map(self, expression: exp.Map) -> exp.Map: ... 595 596 @t.overload 597 def _annotate_map(self, expression: exp.VarMap) -> exp.VarMap: ... 598 599 def _annotate_map(self, expression): 600 self._annotate_args(expression) 601 602 keys = expression.args.get("keys") 603 values = expression.args.get("values") 604 605 map_type = exp.DataType(this=exp.DataType.Type.MAP) 606 if isinstance(keys, exp.Array) and isinstance(values, exp.Array): 607 key_type = seq_get(keys.type.expressions, 0) or exp.DataType.Type.UNKNOWN 608 value_type = seq_get(values.type.expressions, 0) or exp.DataType.Type.UNKNOWN 609 610 if key_type != exp.DataType.Type.UNKNOWN and value_type != exp.DataType.Type.UNKNOWN: 611 map_type.set("expressions", [key_type, value_type]) 612 map_type.set("nested", True) 613 614 self._set_type(expression, map_type) 615 return expression 616 617 def _annotate_to_map(self, expression: exp.ToMap) -> exp.ToMap: 618 self._annotate_args(expression) 619 620 map_type = exp.DataType(this=exp.DataType.Type.MAP) 621 arg = expression.this 622 if arg.is_type(exp.DataType.Type.STRUCT): 623 for coldef in arg.type.expressions: 624 kind = coldef.kind 625 if kind != exp.DataType.Type.UNKNOWN: 626 map_type.set("expressions", [exp.DataType.build("varchar"), kind]) 627 map_type.set("nested", True) 628 break 629 630 self._set_type(expression, map_type) 631 return expression 632 633 def _annotate_extract(self, expression: exp.Extract) -> exp.Extract: 634 self._annotate_args(expression) 635 part = expression.name 636 if part == "TIME": 637 self._set_type(expression, exp.DataType.Type.TIME) 638 elif part == "DATE": 639 self._set_type(expression, exp.DataType.Type.DATE) 640 else: 641 self._set_type(expression, exp.DataType.Type.INT) 642 return expression 643 644 def _annotate_by_array_element(self, expression: exp.Expression) -> exp.Expression: 645 self._annotate_args(expression) 646 647 array_arg = expression.this 648 if array_arg.type.is_type(exp.DataType.Type.ARRAY): 649 element_type = seq_get(array_arg.type.expressions, 0) or exp.DataType.Type.UNKNOWN 650 self._set_type(expression, element_type) 651 else: 652 self._set_type(expression, exp.DataType.Type.UNKNOWN) 653 654 return expression
TypeAnnotator( schema: sqlglot.schema.Schema, annotators: Optional[Dict[Type[~E], Callable[[TypeAnnotator, ~E], ~E]]] = None, coerces_to: Optional[Dict[sqlglot.expressions.DataType.Type, Set[sqlglot.expressions.DataType.Type]]] = None, binary_coercions: Optional[Dict[Tuple[sqlglot.expressions.DataType.Type, sqlglot.expressions.DataType.Type], Callable[[sqlglot.expressions.Expression, sqlglot.expressions.Expression], sqlglot.expressions.DataType.Type]]] = None)
180 def __init__( 181 self, 182 schema: Schema, 183 annotators: t.Optional[AnnotatorsType] = None, 184 coerces_to: t.Optional[t.Dict[exp.DataType.Type, t.Set[exp.DataType.Type]]] = None, 185 binary_coercions: t.Optional[BinaryCoercions] = None, 186 ) -> None: 187 self.schema = schema 188 self.annotators = annotators or Dialect.get_or_raise(schema.dialect).ANNOTATORS 189 self.coerces_to = ( 190 coerces_to or Dialect.get_or_raise(schema.dialect).COERCES_TO or self.COERCES_TO 191 ) 192 self.binary_coercions = binary_coercions or self.BINARY_COERCIONS 193 194 # Caches the ids of annotated sub-Expressions, to ensure we only visit them once 195 self._visited: t.Set[int] = set() 196 197 # Maps an exp.SetOperation's id (e.g. UNION) to its projection types. This is computed if the 198 # exp.SetOperation is the expression of a scope source, as selecting from it multiple times 199 # would reprocess the entire subtree to coerce the types of its operands' projections 200 self._setop_column_types: t.Dict[int, t.Dict[str, exp.DataType | exp.DataType.Type]] = {}
COERCES_TO: Dict[sqlglot.expressions.DataType.Type, Set[sqlglot.expressions.DataType.Type]] =
{<Type.TEXT: 'TEXT'>: set(), <Type.NVARCHAR: 'NVARCHAR'>: {<Type.TEXT: 'TEXT'>}, <Type.VARCHAR: 'VARCHAR'>: {<Type.NVARCHAR: 'NVARCHAR'>, <Type.TEXT: 'TEXT'>}, <Type.NCHAR: 'NCHAR'>: {<Type.NVARCHAR: 'NVARCHAR'>, <Type.VARCHAR: 'VARCHAR'>, <Type.TEXT: 'TEXT'>}, <Type.CHAR: 'CHAR'>: {<Type.NCHAR: 'NCHAR'>, <Type.NVARCHAR: 'NVARCHAR'>, <Type.VARCHAR: 'VARCHAR'>, <Type.TEXT: 'TEXT'>}, <Type.DOUBLE: 'DOUBLE'>: set(), <Type.FLOAT: 'FLOAT'>: {<Type.DOUBLE: 'DOUBLE'>}, <Type.DECIMAL: 'DECIMAL'>: {<Type.DOUBLE: 'DOUBLE'>, <Type.FLOAT: 'FLOAT'>}, <Type.BIGINT: 'BIGINT'>: {<Type.DOUBLE: 'DOUBLE'>, <Type.DECIMAL: 'DECIMAL'>, <Type.FLOAT: 'FLOAT'>}, <Type.INT: 'INT'>: {<Type.DOUBLE: 'DOUBLE'>, <Type.DECIMAL: 'DECIMAL'>, <Type.BIGINT: 'BIGINT'>, <Type.FLOAT: 'FLOAT'>}, <Type.SMALLINT: 'SMALLINT'>: {<Type.DOUBLE: 'DOUBLE'>, <Type.BIGINT: 'BIGINT'>, <Type.FLOAT: 'FLOAT'>, <Type.INT: 'INT'>, <Type.DECIMAL: 'DECIMAL'>}, <Type.TINYINT: 'TINYINT'>: {<Type.DOUBLE: 'DOUBLE'>, <Type.BIGINT: 'BIGINT'>, <Type.FLOAT: 'FLOAT'>, <Type.SMALLINT: 'SMALLINT'>, <Type.INT: 'INT'>, <Type.DECIMAL: 'DECIMAL'>}, <Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>: set(), <Type.TIMESTAMPTZ: 'TIMESTAMPTZ'>: {<Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>}, <Type.TIMESTAMP: 'TIMESTAMP'>: {<Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <Type.TIMESTAMPTZ: 'TIMESTAMPTZ'>}, <Type.DATETIME: 'DATETIME'>: {<Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <Type.TIMESTAMP: 'TIMESTAMP'>, <Type.TIMESTAMPTZ: 'TIMESTAMPTZ'>}, <Type.DATE: 'DATE'>: {<Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <Type.TIMESTAMP: 'TIMESTAMP'>, <Type.DATETIME: 'DATETIME'>, <Type.TIMESTAMPTZ: 'TIMESTAMPTZ'>}, <Type.NULL: 'NULL'>: {<Type.BIGINT: 'BIGINT'>, <Type.TIMESTAMP: 'TIMESTAMP'>, <Type.NCHAR: 'NCHAR'>, <Type.CHAR: 'CHAR'>, <Type.TEXT: 'TEXT'>, <Type.DATETIME: 'DATETIME'>, <Type.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <Type.SMALLINT: 'SMALLINT'>, <Type.DECIMAL: 'DECIMAL'>, <Type.DOUBLE: 'DOUBLE'>, <Type.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <Type.NVARCHAR: 'NVARCHAR'>, <Type.TINYINT: 'TINYINT'>, <Type.FLOAT: 'FLOAT'>, <Type.DATE: 'DATE'>, <Type.INT: 'INT'>, <Type.VARCHAR: 'VARCHAR'>}}
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.CHAR: 'CHAR'>, <Type.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <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.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INTERVAL: 'INTERVAL'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INTERVAL: 'INTERVAL'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INTERVAL: 'INTERVAL'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INTERVAL: 'INTERVAL'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NCHAR: 'NCHAR'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.CHAR: 'CHAR'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TEXT: 'TEXT'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NAME: 'NAME'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.NVARCHAR: 'NVARCHAR'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.VARCHAR: 'VARCHAR'>, <Type.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MONEY: 'MONEY'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UMEDIUMINT: 'UMEDIUMINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT128: 'UINT128'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDOUBLE: 'UDOUBLE'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL: 'DECIMAL'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL64: 'DECIMAL64'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL128: 'DECIMAL128'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLMONEY: 'SMALLMONEY'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT: 'UINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL32: 'DECIMAL32'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL256: 'DECIMAL256'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MONEY: 'MONEY'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UMEDIUMINT: 'UMEDIUMINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT128: 'UINT128'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDOUBLE: 'UDOUBLE'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL: 'DECIMAL'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL64: 'DECIMAL64'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL128: 'DECIMAL128'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLMONEY: 'SMALLMONEY'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT: 'UINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL32: 'DECIMAL32'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL256: 'DECIMAL256'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MONEY: 'MONEY'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UMEDIUMINT: 'UMEDIUMINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT128: 'UINT128'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDOUBLE: 'UDOUBLE'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL: 'DECIMAL'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL64: 'DECIMAL64'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL128: 'DECIMAL128'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLMONEY: 'SMALLMONEY'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT: 'UINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL32: 'DECIMAL32'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL256: 'DECIMAL256'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MONEY: 'MONEY'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UMEDIUMINT: 'UMEDIUMINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT128: 'UINT128'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDOUBLE: 'UDOUBLE'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL: 'DECIMAL'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL64: 'DECIMAL64'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL128: 'DECIMAL128'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLMONEY: 'SMALLMONEY'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT: 'UINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL32: 'DECIMAL32'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL256: 'DECIMAL256'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MONEY: 'MONEY'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UMEDIUMINT: 'UMEDIUMINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT128: 'UINT128'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDOUBLE: 'UDOUBLE'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL: 'DECIMAL'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL64: 'DECIMAL64'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL128: 'DECIMAL128'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLMONEY: 'SMALLMONEY'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT: 'UINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL32: 'DECIMAL32'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL256: 'DECIMAL256'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT: 'INT'>, <Type.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MONEY: 'MONEY'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UMEDIUMINT: 'UMEDIUMINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UTINYINT: 'UTINYINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT128: 'UINT128'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDOUBLE: 'UDOUBLE'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT256: 'UINT256'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL: 'DECIMAL'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGDECIMAL: 'BIGDECIMAL'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DOUBLE: 'DOUBLE'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL64: 'DECIMAL64'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT256: 'INT256'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL128: 'DECIMAL128'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UBIGINT: 'UBIGINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.USMALLINT: 'USMALLINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.FLOAT: 'FLOAT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UDECIMAL: 'UDECIMAL'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLMONEY: 'SMALLMONEY'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.INT128: 'INT128'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIGINT: 'BIGINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.BIT: 'BIT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.SMALLINT: 'SMALLINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.UINT: 'UINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL32: 'DECIMAL32'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.DECIMAL256: 'DECIMAL256'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.MEDIUMINT: 'MEDIUMINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.TINYINT: 'TINYINT'>, <Type.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<Type.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>>}
213 def annotate_scope(self, scope: Scope) -> None: 214 selects = {} 215 for name, source in scope.sources.items(): 216 if not isinstance(source, Scope): 217 continue 218 219 expression = source.expression 220 if isinstance(expression, exp.UDTF): 221 values = [] 222 223 if isinstance(expression, exp.Lateral): 224 if isinstance(expression.this, exp.Explode): 225 values = [expression.this.this] 226 elif isinstance(expression, exp.Unnest): 227 values = [expression] 228 elif not isinstance(expression, exp.TableFromRows): 229 values = expression.expressions[0].expressions 230 231 if not values: 232 continue 233 234 selects[name] = { 235 alias: column.type 236 for alias, column in zip(expression.alias_column_names, values) 237 } 238 elif isinstance(expression, exp.SetOperation) and len(expression.left.selects) == len( 239 expression.right.selects 240 ): 241 selects[name] = col_types = self._setop_column_types.setdefault(id(expression), {}) 242 243 if not col_types: 244 # Process a chain / sub-tree of set operations 245 for set_op in expression.walk( 246 prune=lambda n: not isinstance(n, (exp.SetOperation, exp.Subquery)) 247 ): 248 if not isinstance(set_op, exp.SetOperation): 249 continue 250 251 if set_op.args.get("by_name"): 252 r_type_by_select = { 253 s.alias_or_name: s.type for s in set_op.right.selects 254 } 255 setop_cols = { 256 s.alias_or_name: self._maybe_coerce( 257 t.cast(exp.DataType, s.type), 258 r_type_by_select.get(s.alias_or_name) 259 or exp.DataType.Type.UNKNOWN, 260 ) 261 for s in set_op.left.selects 262 } 263 else: 264 setop_cols = { 265 ls.alias_or_name: self._maybe_coerce( 266 t.cast(exp.DataType, ls.type), t.cast(exp.DataType, rs.type) 267 ) 268 for ls, rs in zip(set_op.left.selects, set_op.right.selects) 269 } 270 271 # Coerce intermediate results with the previously registered types, if they exist 272 for col_name, col_type in setop_cols.items(): 273 col_types[col_name] = self._maybe_coerce( 274 col_type, col_types.get(col_name, exp.DataType.Type.NULL) 275 ) 276 277 else: 278 selects[name] = {s.alias_or_name: s.type for s in expression.selects} 279 280 # First annotate the current scope's column references 281 for col in scope.columns: 282 if not col.table: 283 continue 284 285 source = scope.sources.get(col.table) 286 if isinstance(source, exp.Table): 287 self._set_type(col, self.schema.get_column_type(source, col)) 288 elif source: 289 if col.table in selects and col.name in selects[col.table]: 290 self._set_type(col, selects[col.table][col.name]) 291 elif isinstance(source.expression, exp.Unnest): 292 self._set_type(col, source.expression.type) 293 294 if isinstance(self.schema, MappingSchema): 295 for table_column in scope.table_columns: 296 source = scope.sources.get(table_column.name) 297 298 if isinstance(source, exp.Table): 299 schema = self.schema.find( 300 source, raise_on_missing=False, ensure_data_types=True 301 ) 302 if not isinstance(schema, dict): 303 continue 304 305 struct_type = exp.DataType( 306 this=exp.DataType.Type.STRUCT, 307 expressions=[ 308 exp.ColumnDef(this=exp.to_identifier(c), kind=kind) 309 for c, kind in schema.items() 310 ], 311 nested=True, 312 ) 313 self._set_type(table_column, struct_type) 314 elif ( 315 isinstance(source, Scope) 316 and isinstance(source.expression, exp.Query) 317 and ( 318 source.expression.meta.get("query_type") or exp.DataType.build("UNKNOWN") 319 ).is_type(exp.DataType.Type.STRUCT) 320 ): 321 self._set_type(table_column, source.expression.meta["query_type"]) 322 323 # Then (possibly) annotate the remaining expressions in the scope 324 self._maybe_annotate(scope.expression) 325 326 if self.schema.dialect == "bigquery" and isinstance(scope.expression, exp.Query): 327 struct_type = exp.DataType( 328 this=exp.DataType.Type.STRUCT, 329 expressions=[ 330 exp.ColumnDef( 331 this=exp.to_identifier(select.output_name), 332 kind=select.type.copy() if select.type else None, 333 ) 334 for select in scope.expression.selects 335 ], 336 nested=True, 337 ) 338 339 if not any( 340 cd.kind.is_type(exp.DataType.Type.UNKNOWN) 341 for cd in struct_type.expressions 342 if cd.kind 343 ): 344 # We don't use `_set_type` on purpose here. If we annotated the query directly, then 345 # using it in other contexts (e.g., ARRAY(<query>)) could result in incorrect type 346 # annotations, i.e., it shouldn't be interpreted as a STRUCT value. 347 scope.expression.meta["query_type"] = struct_type