sqlglot.optimizer.annotate_types
1from __future__ import annotations 2 3import functools 4import logging 5import typing as t 6 7from sqlglot import exp 8from sqlglot.dialects.dialect import Dialect 9from sqlglot.helper import ( 10 ensure_list, 11 is_date_unit, 12 is_iso_date, 13 is_iso_datetime, 14 seq_get, 15) 16from sqlglot.optimizer.scope import Scope, traverse_scope 17from sqlglot.schema import MappingSchema, Schema, ensure_schema 18 19if t.TYPE_CHECKING: 20 from sqlglot._typing import B, E 21 22 # TODO (mypyc): should be -> exp.DType but some coercion lambdas return DataType 23 # (e.g. l.type). The original code used t.cast(exp.DType, ...) to satisfy mypy, but 24 # mypyc enforces t.cast at runtime, rejecting DataType values. Widened to accept both. 25 BinaryCoercionFunc = t.Callable[ 26 [exp.Expr, exp.Expr], t.Optional[t.Union[exp.DataType, exp.DType]] 27 ] 28 BinaryCoercions = dict[tuple[exp.DType, exp.DType], BinaryCoercionFunc] 29 30 from sqlglot.dialects.dialect import DialectType 31 from sqlglot.typing import ExprMetadataType 32 33logger = logging.getLogger("sqlglot") 34 35# EXTRACT/DATE_PART specifiers that return BIGINT instead of INT 36BIGINT_EXTRACT_DATE_PARTS = { 37 "EPOCH_SECOND", 38 "EPOCH_MILLISECOND", 39 "EPOCH_MICROSECOND", 40 "EPOCH_NANOSECOND", 41 "NANOSECOND", 42} 43 44 45def annotate_types( 46 expression: E, 47 schema: dict[str, object] | Schema | None = None, 48 expression_metadata: ExprMetadataType | None = None, 49 coerces_to: dict[exp.DType, set[exp.DType]] | None = None, 50 dialect: DialectType = None, 51 overwrite_types: bool = True, 52) -> E: 53 """ 54 Infers the types of an expression, annotating its AST accordingly. 55 56 Example: 57 >>> import sqlglot 58 >>> schema = {"y": {"cola": "SMALLINT"}} 59 >>> sql = "SELECT x.cola + 2.5 AS cola FROM (SELECT y.cola AS cola FROM y AS y) AS x" 60 >>> annotated_expr = annotate_types(sqlglot.parse_one(sql), schema=schema) 61 >>> annotated_expr.expressions[0].type.this # Get the type of "x.cola + 2.5 AS cola" 62 <DType.DOUBLE: 'DOUBLE'> 63 64 Args: 65 expression: Expr to annotate. 66 schema: Database schema. 67 expression_metadata: Maps expression type to corresponding annotation function. 68 coerces_to: Maps expression type to set of types that it can be coerced into. 69 overwrite_types: Re-annotate the existing AST types. 70 71 Returns: 72 The expression annotated with types. 73 """ 74 75 schema = ensure_schema(schema, dialect=dialect) 76 77 return TypeAnnotator( 78 schema=schema, 79 expression_metadata=expression_metadata, 80 coerces_to=coerces_to, 81 overwrite_types=overwrite_types, 82 ).annotate(expression) 83 84 85def _coerce_date_literal(l: exp.Expr, unit: exp.Expr | None) -> exp.DType: 86 date_text = l.name 87 is_iso_date_ = is_iso_date(date_text) 88 89 if is_iso_date_ and is_date_unit(unit): 90 return exp.DType.DATE 91 92 # An ISO date is also an ISO datetime, but not vice versa 93 if is_iso_date_ or is_iso_datetime(date_text): 94 return exp.DType.DATETIME 95 96 return exp.DType.UNKNOWN 97 98 99def _coerce_date(l: exp.Expr, unit: exp.Expr | None) -> exp.DType: 100 if not is_date_unit(unit): 101 return exp.DType.DATETIME 102 return l.type.this if l.type else exp.DType.UNKNOWN 103 104 105def swap_args(func: BinaryCoercionFunc) -> BinaryCoercionFunc: 106 @functools.wraps(func) 107 def _swapped(l: exp.Expr, r: exp.Expr) -> exp.DataType | exp.DType | None: 108 return func(r, l) 109 110 return _swapped 111 112 113def swap_all(coercions: BinaryCoercions) -> BinaryCoercions: 114 return {**coercions, **{(b, a): swap_args(func) for (a, b), func in coercions.items()}} 115 116 117def _build_coerces_to() -> dict[exp.DType, set[exp.DType]]: 118 # Highest-to-lowest type precedence, as specified in Spark's docs (ANSI): 119 # https://spark.apache.org/docs/3.2.0/sql-ref-ansi-compliance.html 120 text_precedence = ( 121 exp.DType.TEXT, 122 exp.DType.NVARCHAR, 123 exp.DType.VARCHAR, 124 exp.DType.NCHAR, 125 exp.DType.CHAR, 126 ) 127 numeric_precedence = ( 128 exp.DType.DECFLOAT, 129 exp.DType.DOUBLE, 130 exp.DType.FLOAT, 131 exp.DType.BIGDECIMAL, 132 exp.DType.DECIMAL, 133 exp.DType.BIGINT, 134 exp.DType.INT, 135 exp.DType.SMALLINT, 136 exp.DType.TINYINT, 137 ) 138 timelike_precedence = ( 139 exp.DType.TIMESTAMPLTZ, 140 exp.DType.TIMESTAMPTZ, 141 exp.DType.TIMESTAMP, 142 exp.DType.DATETIME, 143 exp.DType.DATE, 144 ) 145 146 result: dict[exp.DType, set[exp.DType]] = {} 147 for type_precedence in (text_precedence, numeric_precedence, timelike_precedence): 148 coerces_to: set[exp.DType] = set() 149 for data_type in type_precedence: 150 result[data_type] = coerces_to.copy() 151 coerces_to |= {data_type} 152 return result 153 154 155_COERCES_TO = _build_coerces_to() 156 157 158class TypeAnnotator: 159 NESTED_TYPES: t.ClassVar = { 160 exp.DType.ARRAY, 161 } 162 163 # Specifies what types a given type can be coerced into 164 COERCES_TO: t.ClassVar[dict[exp.DType, set[exp.DType]]] = _COERCES_TO 165 166 # Coercion functions for binary operations. 167 # Map of type pairs to a callable that takes both sides of the binary operation and returns the resulting type. 168 BINARY_COERCIONS: t.ClassVar = { 169 **swap_all( 170 { 171 (t, exp.DType.INTERVAL): lambda l, r: _coerce_date_literal(l, r.args.get("unit")) 172 for t in exp.DataType.TEXT_TYPES 173 } 174 ), 175 **swap_all( 176 { 177 # text + numeric will yield the numeric type to match most dialects' semantics 178 (text, numeric): lambda l, r: ( 179 l.type if l.type in exp.DataType.NUMERIC_TYPES else r.type 180 ) 181 for text in exp.DataType.TEXT_TYPES 182 for numeric in exp.DataType.NUMERIC_TYPES 183 } 184 ), 185 **swap_all( 186 { 187 (exp.DType.DATE, exp.DType.INTERVAL): lambda l, r: _coerce_date( 188 l, r.args.get("unit") 189 ), 190 } 191 ), 192 } 193 194 def __init__( 195 self, 196 schema: Schema, 197 expression_metadata: ExprMetadataType | None = None, 198 coerces_to: dict[exp.DType, set[exp.DType]] | None = None, 199 binary_coercions: BinaryCoercions | None = None, 200 overwrite_types: bool = True, 201 ) -> None: 202 self.schema = schema 203 dialect = schema.dialect or Dialect() 204 self.dialect = dialect 205 self.expression_metadata = expression_metadata or dialect.EXPRESSION_METADATA 206 self.coerces_to = coerces_to or dialect.COERCES_TO or self.COERCES_TO 207 self.binary_coercions = binary_coercions or self.BINARY_COERCIONS 208 209 # Caches the ids of annotated sub-Exprs, to ensure we only visit them once 210 self._visited: set[int] = set() 211 212 # Caches NULL-annotated expressions to set them to UNKNOWN after type inference is completed 213 self._null_expressions: dict[int, exp.Expr] = {} 214 215 # Databricks and Spark ≥v3 actually support NULL (i.e., VOID) as a type 216 self._supports_null_type = dialect.SUPPORTS_NULL_TYPE 217 218 # Maps an exp.SetOperation's id (e.g. UNION) to its projection types. This is computed if the 219 # exp.SetOperation is the expression of a scope source, as selecting from it multiple times 220 # would reprocess the entire subtree to coerce the types of its operands' projections 221 self._setop_column_types: dict[int, dict[str, exp.DataType | exp.DType]] = {} 222 223 # When set to False, this enables partial annotation by skipping already-annotated nodes 224 self._overwrite_types = overwrite_types 225 226 # Maps Scope to its corresponding selected sources 227 self._scope_selects: dict[Scope, dict[str, dict[str, t.Any]]] = {} 228 229 def clear(self) -> None: 230 self._visited.clear() 231 self._null_expressions.clear() 232 self._setop_column_types.clear() 233 self._scope_selects.clear() 234 235 # TODO (mypyc): should be expression: E -> E but mypyc resolves the TypeVar 236 # to the isinstance-narrowed type, causing runtime type check failures. 237 def _set_type( 238 self, expression: exp.Expr, target_type: exp.DataType | exp.DType | None 239 ) -> exp.Expr: 240 prev_type = expression.type 241 expression_id = id(expression) 242 243 # TODO (mypyc): expression.type = ... should work but mypyc compiles the property 244 # setter to enforce the getter's return type (Optional[DataType]), rejecting DType. 245 # Bypass by converting and assigning to _type directly. 246 dtype = target_type or exp.DType.UNKNOWN 247 expression._type = dtype if isinstance(dtype, exp.DataType) else exp.DataType.build(dtype) 248 self._visited.add(expression_id) 249 250 if ( 251 not self._supports_null_type 252 and t.cast(exp.DataType, expression.type).this == exp.DType.NULL 253 ): 254 self._null_expressions[expression_id] = expression 255 elif prev_type and t.cast(exp.DataType, prev_type).this == exp.DType.NULL: 256 self._null_expressions.pop(expression_id, None) 257 258 return expression 259 260 def annotate(self, expression: E, annotate_scope: bool = True) -> E: 261 # This flag is used to avoid costly scope traversals when we only care about annotating 262 # non-column expressions (partial type inference), e.g., when simplifying in the optimizer 263 if annotate_scope: 264 for scope in traverse_scope(expression): 265 self.annotate_scope(scope) 266 267 # This takes care of non-traversable expressions 268 self._annotate_expression(expression) 269 270 # Replace NULL type with the default type of the targeted dialect, since the former is not an actual type; 271 # it is mostly used to aid type coercion, e.g. in query set operations. 272 # TODO (mypyc): uses list() + _set_type instead of direct expr.type = ... because 273 # mypyc's property setter bypass rejects DType, and _set_type modifies the dict. 274 for expr in list(self._null_expressions.values()): 275 self._set_type(expr, self.dialect.DEFAULT_NULL_TYPE) 276 277 return expression 278 279 def _get_scope_selects(self, scope: Scope) -> dict[str, dict[str, t.Any]]: 280 if scope not in self._scope_selects: 281 selects = {} 282 for name, source in scope.sources.items(): 283 if not isinstance(source, Scope): 284 continue 285 286 expression = source.expression 287 if isinstance(expression, exp.UDTF): 288 values = [] 289 290 if isinstance(expression, exp.Lateral): 291 if isinstance(expression.this, exp.Explode): 292 values = [expression.this.this] 293 elif isinstance(expression, exp.Unnest): 294 values = [expression] 295 elif not isinstance(expression, exp.TableFromRows): 296 values = expression.expressions[0].expressions 297 298 if not values: 299 continue 300 301 alias_column_names = expression.alias_column_names 302 303 if ( 304 isinstance(expression, exp.Unnest) 305 and expression.type 306 and expression.type.is_type(exp.DType.STRUCT) 307 ): 308 selects[name] = { 309 col_def.name: t.cast(t.Union[exp.DataType, exp.DType], col_def.kind) 310 for col_def in expression.type.expressions 311 if isinstance(col_def, exp.ColumnDef) and col_def.kind 312 } 313 else: 314 selects[name] = { 315 alias: column.type for alias, column in zip(alias_column_names, values) 316 } 317 elif isinstance(expression, exp.SetOperation) and len( 318 expression.left.selects 319 ) == len(expression.right.selects): 320 selects[name] = self._get_setop_column_types(expression) 321 elif isinstance(expression, exp.Selectable): 322 selects[name] = {s.alias_or_name: s.type for s in expression.selects if s.type} 323 324 self._scope_selects[scope] = selects 325 326 return self._scope_selects[scope] 327 328 def annotate_scope(self, scope: Scope) -> None: 329 if isinstance(self.schema, MappingSchema): 330 for table_column in scope.table_columns: 331 source = scope.sources.get(table_column.name) 332 333 if isinstance(source, exp.Table): 334 schema = self.schema.find( 335 source, raise_on_missing=False, ensure_data_types=True 336 ) 337 if not isinstance(schema, dict): 338 continue 339 340 struct_type = exp.DataType( 341 this=exp.DType.STRUCT, 342 expressions=[ 343 exp.ColumnDef(this=exp.to_identifier(str(c)), kind=kind) 344 for c, kind in schema.items() 345 ], 346 nested=True, 347 ) 348 self._set_type(table_column, struct_type) 349 elif ( 350 isinstance(source, Scope) 351 and isinstance(source.expression, exp.Query) 352 and ( 353 source.expression.meta.get("query_type") or exp.DType.UNKNOWN.into_expr() 354 ).is_type(exp.DType.STRUCT) 355 ): 356 self._set_type(table_column, source.expression.meta["query_type"]) 357 358 # Iterate through all the expressions of the current scope in post-order, and annotate 359 self._annotate_expression(scope.expression, scope) 360 self._fixup_order_by_aliases(scope) 361 362 if self.dialect.QUERY_RESULTS_ARE_STRUCTS and isinstance(scope.expression, exp.Query): 363 struct_type = exp.DataType( 364 this=exp.DType.STRUCT, 365 expressions=[ 366 exp.ColumnDef( 367 this=exp.to_identifier(select.output_name), 368 kind=select.type.copy() if select.type else None, 369 ) 370 for select in scope.expression.selects 371 ], 372 nested=True, 373 ) 374 375 if not any( 376 cd.kind.is_type(exp.DType.UNKNOWN) for cd in struct_type.expressions if cd.kind 377 ): 378 # We don't use `_set_type` on purpose here. If we annotated the query directly, then 379 # using it in other contexts (e.g., ARRAY(<query>)) could result in incorrect type 380 # annotations, i.e., it shouldn't be interpreted as a STRUCT value. 381 scope.expression.meta["query_type"] = struct_type 382 383 def _annotate_expression( 384 self, 385 expression: exp.Expr, 386 scope: Scope | None = None, 387 ) -> None: 388 stack = [(expression, False)] 389 390 while stack: 391 expr, children_annotated = stack.pop() 392 393 if id(expr) in self._visited or ( 394 not self._overwrite_types and expr.type and not expr.is_type(exp.DType.UNKNOWN) 395 ): 396 continue # We've already inferred the expression's type 397 398 if not children_annotated: 399 stack.append((expr, True)) 400 for child_expr in expr.iter_expressions(): 401 stack.append((child_expr, False)) 402 continue 403 404 if scope and isinstance(expr, exp.Column) and expr.table: 405 source = None 406 source_scope: Scope | None = scope 407 while source_scope and not source: 408 source = source_scope.sources.get(expr.table) 409 if not source: 410 source_scope = source_scope.parent 411 412 if isinstance(source, exp.Table): 413 self._set_type(expr, self.schema.get_column_type(source, expr)) 414 elif source and source_scope: 415 col_type = ( 416 self._get_scope_selects(source_scope).get(expr.table, {}).get(expr.name) 417 ) 418 if col_type: 419 self._set_type(expr, col_type) 420 elif isinstance(source.expression, exp.Unnest): 421 self._set_type(expr, source.expression.type) 422 else: 423 self._set_type(expr, exp.DType.UNKNOWN) 424 else: 425 self._set_type(expr, exp.DType.UNKNOWN) 426 427 if expr.is_type(exp.DType.JSON) and (dot_parts := expr.meta.get("dot_parts")): 428 # JSON dot access is case sensitive across all dialects, so we need to undo the normalization. 429 i = iter(dot_parts) 430 parent = expr.parent 431 while isinstance(parent, exp.Dot): 432 parent.expression.replace(exp.to_identifier(next(i), quoted=True)) 433 parent = parent.parent 434 435 expr.meta.pop("dot_parts", None) 436 437 if expr.type and expr.type.args.get("nullable") is False: 438 expr.meta["nonnull"] = True 439 continue 440 441 spec = self.expression_metadata.get(expr.__class__) 442 443 if spec and (annotator := spec.get("annotator")): 444 annotator(self, expr) 445 elif spec and (returns := spec.get("returns")): 446 self._set_type(expr, returns) 447 else: 448 self._set_type(expr, exp.DType.UNKNOWN) 449 450 def _fixup_order_by_aliases(self, scope: Scope) -> None: 451 query = scope.expression 452 if not isinstance(query, exp.Query): 453 return 454 455 order = query.args.get("order") 456 if not order: 457 return 458 459 # Build alias -> type map from fully-annotated projections (last match wins, 460 # consistent with how _expand_alias_refs handles duplicate aliases). 461 alias_types: dict[str, exp.DataType | exp.DType] = {} 462 for sel in query.selects: 463 if ( 464 isinstance(sel, exp.Alias) 465 and sel.this.type 466 and not sel.this.is_type(exp.DType.UNKNOWN) 467 ): 468 alias_types[sel.alias] = sel.this.type 469 470 if not alias_types: 471 return 472 473 for ordered in order.expressions: 474 alias_cols = [ 475 c for c in ordered.find_all(exp.Column) if not c.table and c.name in alias_types 476 ] 477 for col in alias_cols: 478 self._set_type(col, alias_types[col.name]) 479 480 if alias_cols: 481 for node in ordered.walk(prune=lambda n: isinstance(n, exp.Subquery)): 482 if not isinstance(node, (exp.Column, exp.Literal)): 483 self._visited.discard(id(node)) 484 self._annotate_expression(ordered, scope) 485 486 def _maybe_coerce( 487 self, 488 type1: exp.DataType | exp.DType, 489 type2: exp.DataType | exp.DType, 490 ) -> exp.DataType | exp.DType: 491 """ 492 Returns type2 if type1 can be coerced into it, otherwise type1. 493 494 If either type is parameterized (e.g. DECIMAL(18, 2) contains two parameters), 495 we assume type1 does not coerce into type2, so we also return it in this case. 496 """ 497 if isinstance(type1, exp.DataType): 498 if type1.expressions: 499 return type1 500 type1_value = type1.this 501 else: 502 type1_value = type1 503 504 if isinstance(type2, exp.DataType): 505 if type2.expressions: 506 return type2 507 type2_value = type2.this 508 else: 509 type2_value = type2 510 511 # We propagate the UNKNOWN type upwards if found 512 if exp.DType.UNKNOWN in (type1_value, type2_value): 513 return exp.DType.UNKNOWN 514 515 if type1_value == exp.DType.NULL: 516 return type2_value 517 if type2_value == exp.DType.NULL: 518 return type1_value 519 520 return type2_value if type2_value in self.coerces_to.get(type1_value, {}) else type1_value 521 522 def _get_setop_column_types( 523 self, setop: exp.SetOperation 524 ) -> dict[str, exp.DataType | exp.DType]: 525 """ 526 Computes and returns the coerced column types for a SetOperation. 527 528 This handles UNION, INTERSECT, EXCEPT, etc., coercing types across 529 left and right operands for all projections/columns. 530 531 Args: 532 setop: The SetOperation expression to analyze 533 534 Returns: 535 Dictionary mapping column names to their coerced types 536 """ 537 setop_id = id(setop) 538 if setop_id in self._setop_column_types: 539 return self._setop_column_types[setop_id] 540 541 col_types: dict[str, exp.DataType | exp.DType] = {} 542 543 # Validate that left and right have same number of projections 544 if not ( 545 isinstance(setop, exp.SetOperation) 546 and setop.left.selects 547 and setop.right.selects 548 and len(setop.left.selects) == len(setop.right.selects) 549 ): 550 return col_types 551 552 # Process a chain / sub-tree of set operations 553 for set_op in setop.walk( 554 prune=lambda n: not isinstance(n, (exp.SetOperation, exp.Subquery)) 555 ): 556 if not isinstance(set_op, exp.SetOperation): 557 continue 558 559 if set_op.args.get("by_name"): 560 r_type_by_select = {s.alias_or_name: s.type for s in set_op.right.selects} 561 setop_cols = { 562 s.alias_or_name: self._maybe_coerce( 563 t.cast(exp.DataType, s.type), 564 r_type_by_select.get(s.alias_or_name) or exp.DType.UNKNOWN, 565 ) 566 for s in set_op.left.selects 567 } 568 else: 569 setop_cols = { 570 ls.alias_or_name: self._maybe_coerce( 571 t.cast(exp.DataType, ls.type), t.cast(exp.DataType, rs.type) 572 ) 573 for ls, rs in zip(set_op.left.selects, set_op.right.selects) 574 } 575 576 # Coerce intermediate results with the previously registered types, if they exist 577 for col_name, col_type in setop_cols.items(): 578 col_types[col_name] = self._maybe_coerce( 579 col_type, col_types.get(col_name, exp.DType.NULL) 580 ) 581 582 self._setop_column_types[setop_id] = col_types 583 return col_types 584 585 def _annotate_binary(self, expression: B) -> B: 586 left, right = expression.left, expression.right 587 if not left or not right: 588 expression_sql = expression.sql(self.dialect) 589 logger.warning(f"Failed to annotate badly formed binary expression: {expression_sql}") 590 self._set_type(expression, None) 591 return expression 592 593 left_type, right_type = left.type.this, right.type.this # type: ignore 594 595 # TODO (mypyc): should be isinstance(expression, (exp.Connector, exp.Predicate)) but 596 # mypyc narrows the variable to the first type in a tuple/or isinstance check when 597 # the types are sibling @trait classes, rejecting instances of the second type. 598 if issubclass(type(expression), (exp.Connector, exp.Predicate)): 599 self._set_type(expression, exp.DType.BOOLEAN) 600 elif (left_type, right_type) in self.binary_coercions: 601 self._set_type(expression, self.binary_coercions[(left_type, right_type)](left, right)) 602 else: 603 self._annotate_by_args(expression, left, right) 604 605 if isinstance(expression, exp.Is) or ( 606 left.meta.get("nonnull") is True and right.meta.get("nonnull") is True 607 ): 608 expression.meta["nonnull"] = True 609 610 return expression 611 612 def _annotate_unary(self, expression: E) -> E: 613 if isinstance(expression, exp.Not): 614 self._set_type(expression, exp.DType.BOOLEAN) 615 else: 616 self._set_type(expression, expression.this.type) 617 618 if expression.this.meta.get("nonnull") is True: 619 expression.meta["nonnull"] = True 620 621 return expression 622 623 def _annotate_literal(self, expression: exp.Literal) -> exp.Literal: 624 if expression.is_string: 625 self._set_type(expression, exp.DType.VARCHAR) 626 elif expression.is_int: 627 self._set_type(expression, exp.DType.INT) 628 else: 629 self._set_type(expression, exp.DType.DOUBLE) 630 631 expression.meta["nonnull"] = True 632 633 return expression 634 635 def _annotate_by_args( 636 self, 637 expression: E, 638 *args: str | exp.Expr, 639 promote: bool = False, 640 array: bool = False, 641 ) -> E: 642 literal_type = None 643 non_literal_type = None 644 nested_type = None 645 646 for arg in args: 647 if isinstance(arg, str): 648 expressions = expression.args.get(arg) 649 else: 650 expressions = arg 651 652 for expr in ensure_list(expressions): 653 expr_type = expr.type 654 655 if expr_type.is_type(exp.DType.UNKNOWN): 656 self._set_type(expression, exp.DType.UNKNOWN) 657 return expression 658 659 if nested_type: 660 continue 661 662 # Stop coercing at the first nested data type found 663 if expr_type.args.get("nested"): 664 nested_type = expr_type 665 elif isinstance(expr, exp.Literal): 666 literal_type = self._maybe_coerce(literal_type or expr_type, expr_type) 667 else: 668 non_literal_type = self._maybe_coerce(non_literal_type or expr_type, expr_type) 669 670 result_type = None 671 672 if nested_type: 673 result_type = nested_type 674 elif literal_type and non_literal_type: 675 if self.dialect.PRIORITIZE_NON_LITERAL_TYPES: 676 literal_this_type = ( 677 literal_type.this if isinstance(literal_type, exp.DataType) else literal_type 678 ) 679 non_literal_this_type = ( 680 non_literal_type.this 681 if isinstance(non_literal_type, exp.DataType) 682 else non_literal_type 683 ) 684 if ( 685 literal_this_type in exp.DataType.INTEGER_TYPES 686 and non_literal_this_type in exp.DataType.INTEGER_TYPES 687 ) or ( 688 literal_this_type in exp.DataType.REAL_TYPES 689 and non_literal_this_type in exp.DataType.REAL_TYPES 690 ): 691 result_type = non_literal_type 692 else: 693 result_type = literal_type or non_literal_type or exp.DType.UNKNOWN 694 695 self._set_type( 696 expression, 697 result_type or self._maybe_coerce(non_literal_type, literal_type), # type: ignore 698 ) 699 700 if promote: 701 if expression.type.this in exp.DataType.INTEGER_TYPES: # type: ignore 702 self._set_type(expression, exp.DType.BIGINT) 703 elif expression.type.this in exp.DataType.FLOAT_TYPES: # type: ignore 704 self._set_type(expression, exp.DType.DOUBLE) 705 706 if array: 707 self._set_type( 708 expression, 709 exp.DataType(this=exp.DType.ARRAY, expressions=[expression.type], nested=True), 710 ) 711 712 return expression 713 714 def _annotate_timeunit( 715 self, expression: exp.TimeUnit | exp.DateTrunc 716 ) -> exp.TimeUnit | exp.DateTrunc: 717 if expression.this.type.this in exp.DataType.TEXT_TYPES: 718 datatype = _coerce_date_literal(expression.this, expression.unit) 719 elif expression.this.type.this in exp.DataType.TEMPORAL_TYPES: 720 datatype = _coerce_date(expression.this, expression.unit) 721 else: 722 datatype = exp.DType.UNKNOWN 723 724 self._set_type(expression, datatype) 725 return expression 726 727 def _annotate_bracket(self, expression: exp.Bracket) -> exp.Bracket: 728 bracket_arg = expression.expressions[0] 729 this = expression.this 730 731 if isinstance(bracket_arg, exp.Slice): 732 self._set_type(expression, this.type) 733 elif this.type.is_type(exp.DType.ARRAY): 734 self._set_type(expression, seq_get(this.type.expressions, 0)) 735 elif isinstance(this, (exp.Map, exp.VarMap)) and bracket_arg in this.keys: 736 index = this.keys.index(bracket_arg) 737 value = seq_get(this.values, index) 738 self._set_type(expression, value.type if value else None) 739 else: 740 self._set_type(expression, exp.DType.UNKNOWN) 741 742 return expression 743 744 def _annotate_div(self, expression: exp.Div) -> exp.Div: 745 left_type, right_type = expression.left.type.this, expression.right.type.this # type: ignore 746 747 if ( 748 expression.args.get("typed") 749 and left_type in exp.DataType.INTEGER_TYPES 750 and right_type in exp.DataType.INTEGER_TYPES 751 ): 752 self._set_type(expression, exp.DType.BIGINT) 753 else: 754 self._set_type(expression, self._maybe_coerce(left_type, right_type)) 755 if expression.type and expression.type.this not in exp.DataType.REAL_TYPES: 756 self._set_type(expression, self._maybe_coerce(expression.type, exp.DType.DOUBLE)) 757 758 return expression 759 760 def _annotate_dot(self, expression: exp.Dot) -> exp.Dot: 761 self._set_type(expression, None) 762 763 # Propagate type from qualified UDF calls (e.g., db.my_udf(...)) 764 if isinstance(expression.expression, exp.Anonymous): 765 self._set_type(expression, expression.expression.type) 766 return expression 767 768 this_type = expression.this.type 769 770 if this_type and this_type.is_type(exp.DType.STRUCT): 771 for e in this_type.expressions: 772 if e.name == expression.expression.name: 773 self._set_type(expression, e.kind) 774 break 775 776 return expression 777 778 def _annotate_explode(self, expression: exp.Explode) -> exp.Explode: 779 self._set_type(expression, seq_get(expression.this.type.expressions, 0)) 780 return expression 781 782 def _annotate_unnest(self, expression: exp.Unnest) -> exp.Unnest: 783 child = seq_get(expression.expressions, 0) 784 785 if child and child.is_type(exp.DType.ARRAY): 786 expr_type = seq_get(child.type.expressions, 0) 787 else: 788 expr_type = None 789 790 self._set_type(expression, expr_type) 791 return expression 792 793 def _annotate_subquery(self, expression: exp.Subquery) -> exp.Subquery: 794 # For scalar subqueries (subqueries with a single projection), infer the type 795 # from that single projection. This allows type propagation in cases like: 796 # SELECT (SELECT 1 AS c) AS c 797 query = expression.unnest() 798 799 if isinstance(query, exp.Query): 800 selects = query.selects 801 if len(selects) == 1: 802 self._set_type(expression, selects[0].type) 803 return expression 804 805 self._set_type(expression, exp.DType.UNKNOWN) 806 return expression 807 808 def _annotate_struct_value(self, expression: exp.Expr) -> exp.DataType | None | exp.ColumnDef: 809 # Case: STRUCT(key AS value) 810 this: exp.Expr | None = None 811 kind = expression.type 812 813 if alias := expression.args.get("alias"): 814 this = alias.copy() 815 elif expression.expression: 816 # Case: STRUCT(key = value) or STRUCT(key := value) 817 this = expression.this.copy() 818 kind = expression.expression.type 819 elif isinstance(expression, exp.Column): 820 # Case: STRUCT(c) 821 this = expression.this.copy() 822 823 if kind and kind.is_type(exp.DType.UNKNOWN): 824 return None 825 826 if this: 827 return exp.ColumnDef(this=this, kind=kind) 828 829 return kind 830 831 def _annotate_struct(self, expression: exp.Struct) -> exp.Struct: 832 expressions = [] 833 for expr in expression.expressions: 834 struct_field_type = self._annotate_struct_value(expr) 835 if struct_field_type is None: 836 self._set_type(expression, None) 837 return expression 838 839 expressions.append(struct_field_type) 840 841 self._set_type( 842 expression, 843 exp.DataType(this=exp.DType.STRUCT, expressions=expressions, nested=True), 844 ) 845 return expression 846 847 @t.overload 848 def _annotate_map(self, expression: exp.Map) -> exp.Map: ... 849 850 @t.overload 851 def _annotate_map(self, expression: exp.VarMap) -> exp.VarMap: ... 852 853 def _annotate_map(self, expression): 854 keys = expression.args.get("keys") 855 values = expression.args.get("values") 856 857 map_type = exp.DataType(this=exp.DType.MAP) 858 if isinstance(keys, exp.Array) and isinstance(values, exp.Array): 859 key_type = seq_get(keys.type.expressions, 0) or exp.DType.UNKNOWN 860 value_type = seq_get(values.type.expressions, 0) or exp.DType.UNKNOWN 861 862 if key_type != exp.DType.UNKNOWN and value_type != exp.DType.UNKNOWN: 863 map_type.set("expressions", [key_type, value_type]) 864 map_type.set("nested", True) 865 866 self._set_type(expression, map_type) 867 return expression 868 869 def _annotate_to_map(self, expression: exp.ToMap) -> exp.ToMap: 870 map_type = exp.DataType(this=exp.DType.MAP) 871 arg = expression.this 872 if arg.is_type(exp.DType.STRUCT): 873 for coldef in arg.type.expressions: 874 kind = coldef.kind 875 if kind != exp.DType.UNKNOWN: 876 map_type.set("expressions", [exp.DType.VARCHAR.into_expr(), kind]) 877 map_type.set("nested", True) 878 break 879 880 self._set_type(expression, map_type) 881 return expression 882 883 def _annotate_extract(self, expression: exp.Extract) -> exp.Extract: 884 part = expression.name 885 if part == "TIME": 886 self._set_type(expression, exp.DType.TIME) 887 elif part == "DATE": 888 self._set_type(expression, exp.DType.DATE) 889 elif part in BIGINT_EXTRACT_DATE_PARTS: 890 self._set_type(expression, exp.DType.BIGINT) 891 else: 892 self._set_type(expression, exp.DType.INT) 893 return expression 894 895 def _annotate_by_array_element(self, expression: exp.Expr) -> exp.Expr: 896 array_arg = expression.this 897 if array_arg.type.is_type(exp.DType.ARRAY): 898 element_type = seq_get(array_arg.type.expressions, 0) or exp.DType.UNKNOWN 899 self._set_type(expression, element_type) 900 else: 901 self._set_type(expression, exp.DType.UNKNOWN) 902 903 return expression
logger =
<Logger sqlglot (WARNING)>
BIGINT_EXTRACT_DATE_PARTS =
{'EPOCH_MICROSECOND', 'NANOSECOND', 'EPOCH_NANOSECOND', 'EPOCH_MILLISECOND', 'EPOCH_SECOND'}
def
annotate_types( expression: ~E, schema: dict[str, object] | sqlglot.schema.Schema | None = None, expression_metadata: dict[type[sqlglot.expressions.core.Expr], dict[str, typing.Any]] | None = None, coerces_to: dict[sqlglot.expressions.datatypes.DType, set[sqlglot.expressions.datatypes.DType]] | None = None, dialect: Union[str, sqlglot.dialects.Dialect, type[sqlglot.dialects.Dialect], NoneType] = None, overwrite_types: bool = True) -> ~E:
46def annotate_types( 47 expression: E, 48 schema: dict[str, object] | Schema | None = None, 49 expression_metadata: ExprMetadataType | None = None, 50 coerces_to: dict[exp.DType, set[exp.DType]] | None = None, 51 dialect: DialectType = None, 52 overwrite_types: bool = True, 53) -> E: 54 """ 55 Infers the types of an expression, annotating its AST accordingly. 56 57 Example: 58 >>> import sqlglot 59 >>> schema = {"y": {"cola": "SMALLINT"}} 60 >>> sql = "SELECT x.cola + 2.5 AS cola FROM (SELECT y.cola AS cola FROM y AS y) AS x" 61 >>> annotated_expr = annotate_types(sqlglot.parse_one(sql), schema=schema) 62 >>> annotated_expr.expressions[0].type.this # Get the type of "x.cola + 2.5 AS cola" 63 <DType.DOUBLE: 'DOUBLE'> 64 65 Args: 66 expression: Expr to annotate. 67 schema: Database schema. 68 expression_metadata: Maps expression type to corresponding annotation function. 69 coerces_to: Maps expression type to set of types that it can be coerced into. 70 overwrite_types: Re-annotate the existing AST types. 71 72 Returns: 73 The expression annotated with types. 74 """ 75 76 schema = ensure_schema(schema, dialect=dialect) 77 78 return TypeAnnotator( 79 schema=schema, 80 expression_metadata=expression_metadata, 81 coerces_to=coerces_to, 82 overwrite_types=overwrite_types, 83 ).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" <DType.DOUBLE: 'DOUBLE'>
Arguments:
- expression: Expr to annotate.
- schema: Database schema.
- expression_metadata: Maps expression type to corresponding annotation function.
- coerces_to: Maps expression type to set of types that it can be coerced into.
- overwrite_types: Re-annotate the existing AST types.
Returns:
The expression annotated with types.
def
swap_args( func: Callable[[sqlglot.expressions.core.Expr, sqlglot.expressions.core.Expr], Union[sqlglot.expressions.datatypes.DataType, sqlglot.expressions.datatypes.DType, NoneType]]) -> Callable[[sqlglot.expressions.core.Expr, sqlglot.expressions.core.Expr], Union[sqlglot.expressions.datatypes.DataType, sqlglot.expressions.datatypes.DType, NoneType]]:
def
swap_all( coercions: dict[tuple[sqlglot.expressions.datatypes.DType, sqlglot.expressions.datatypes.DType], typing.Callable[[sqlglot.expressions.core.Expr, sqlglot.expressions.core.Expr], typing.Union[sqlglot.expressions.datatypes.DataType, sqlglot.expressions.datatypes.DType, NoneType]]]) -> dict[tuple[sqlglot.expressions.datatypes.DType, sqlglot.expressions.datatypes.DType], typing.Callable[[sqlglot.expressions.core.Expr, sqlglot.expressions.core.Expr], typing.Union[sqlglot.expressions.datatypes.DataType, sqlglot.expressions.datatypes.DType, NoneType]]]:
class
TypeAnnotator:
159class TypeAnnotator: 160 NESTED_TYPES: t.ClassVar = { 161 exp.DType.ARRAY, 162 } 163 164 # Specifies what types a given type can be coerced into 165 COERCES_TO: t.ClassVar[dict[exp.DType, set[exp.DType]]] = _COERCES_TO 166 167 # Coercion functions for binary operations. 168 # Map of type pairs to a callable that takes both sides of the binary operation and returns the resulting type. 169 BINARY_COERCIONS: t.ClassVar = { 170 **swap_all( 171 { 172 (t, exp.DType.INTERVAL): lambda l, r: _coerce_date_literal(l, r.args.get("unit")) 173 for t in exp.DataType.TEXT_TYPES 174 } 175 ), 176 **swap_all( 177 { 178 # text + numeric will yield the numeric type to match most dialects' semantics 179 (text, numeric): lambda l, r: ( 180 l.type if l.type in exp.DataType.NUMERIC_TYPES else r.type 181 ) 182 for text in exp.DataType.TEXT_TYPES 183 for numeric in exp.DataType.NUMERIC_TYPES 184 } 185 ), 186 **swap_all( 187 { 188 (exp.DType.DATE, exp.DType.INTERVAL): lambda l, r: _coerce_date( 189 l, r.args.get("unit") 190 ), 191 } 192 ), 193 } 194 195 def __init__( 196 self, 197 schema: Schema, 198 expression_metadata: ExprMetadataType | None = None, 199 coerces_to: dict[exp.DType, set[exp.DType]] | None = None, 200 binary_coercions: BinaryCoercions | None = None, 201 overwrite_types: bool = True, 202 ) -> None: 203 self.schema = schema 204 dialect = schema.dialect or Dialect() 205 self.dialect = dialect 206 self.expression_metadata = expression_metadata or dialect.EXPRESSION_METADATA 207 self.coerces_to = coerces_to or dialect.COERCES_TO or self.COERCES_TO 208 self.binary_coercions = binary_coercions or self.BINARY_COERCIONS 209 210 # Caches the ids of annotated sub-Exprs, to ensure we only visit them once 211 self._visited: set[int] = set() 212 213 # Caches NULL-annotated expressions to set them to UNKNOWN after type inference is completed 214 self._null_expressions: dict[int, exp.Expr] = {} 215 216 # Databricks and Spark ≥v3 actually support NULL (i.e., VOID) as a type 217 self._supports_null_type = dialect.SUPPORTS_NULL_TYPE 218 219 # Maps an exp.SetOperation's id (e.g. UNION) to its projection types. This is computed if the 220 # exp.SetOperation is the expression of a scope source, as selecting from it multiple times 221 # would reprocess the entire subtree to coerce the types of its operands' projections 222 self._setop_column_types: dict[int, dict[str, exp.DataType | exp.DType]] = {} 223 224 # When set to False, this enables partial annotation by skipping already-annotated nodes 225 self._overwrite_types = overwrite_types 226 227 # Maps Scope to its corresponding selected sources 228 self._scope_selects: dict[Scope, dict[str, dict[str, t.Any]]] = {} 229 230 def clear(self) -> None: 231 self._visited.clear() 232 self._null_expressions.clear() 233 self._setop_column_types.clear() 234 self._scope_selects.clear() 235 236 # TODO (mypyc): should be expression: E -> E but mypyc resolves the TypeVar 237 # to the isinstance-narrowed type, causing runtime type check failures. 238 def _set_type( 239 self, expression: exp.Expr, target_type: exp.DataType | exp.DType | None 240 ) -> exp.Expr: 241 prev_type = expression.type 242 expression_id = id(expression) 243 244 # TODO (mypyc): expression.type = ... should work but mypyc compiles the property 245 # setter to enforce the getter's return type (Optional[DataType]), rejecting DType. 246 # Bypass by converting and assigning to _type directly. 247 dtype = target_type or exp.DType.UNKNOWN 248 expression._type = dtype if isinstance(dtype, exp.DataType) else exp.DataType.build(dtype) 249 self._visited.add(expression_id) 250 251 if ( 252 not self._supports_null_type 253 and t.cast(exp.DataType, expression.type).this == exp.DType.NULL 254 ): 255 self._null_expressions[expression_id] = expression 256 elif prev_type and t.cast(exp.DataType, prev_type).this == exp.DType.NULL: 257 self._null_expressions.pop(expression_id, None) 258 259 return expression 260 261 def annotate(self, expression: E, annotate_scope: bool = True) -> E: 262 # This flag is used to avoid costly scope traversals when we only care about annotating 263 # non-column expressions (partial type inference), e.g., when simplifying in the optimizer 264 if annotate_scope: 265 for scope in traverse_scope(expression): 266 self.annotate_scope(scope) 267 268 # This takes care of non-traversable expressions 269 self._annotate_expression(expression) 270 271 # Replace NULL type with the default type of the targeted dialect, since the former is not an actual type; 272 # it is mostly used to aid type coercion, e.g. in query set operations. 273 # TODO (mypyc): uses list() + _set_type instead of direct expr.type = ... because 274 # mypyc's property setter bypass rejects DType, and _set_type modifies the dict. 275 for expr in list(self._null_expressions.values()): 276 self._set_type(expr, self.dialect.DEFAULT_NULL_TYPE) 277 278 return expression 279 280 def _get_scope_selects(self, scope: Scope) -> dict[str, dict[str, t.Any]]: 281 if scope not in self._scope_selects: 282 selects = {} 283 for name, source in scope.sources.items(): 284 if not isinstance(source, Scope): 285 continue 286 287 expression = source.expression 288 if isinstance(expression, exp.UDTF): 289 values = [] 290 291 if isinstance(expression, exp.Lateral): 292 if isinstance(expression.this, exp.Explode): 293 values = [expression.this.this] 294 elif isinstance(expression, exp.Unnest): 295 values = [expression] 296 elif not isinstance(expression, exp.TableFromRows): 297 values = expression.expressions[0].expressions 298 299 if not values: 300 continue 301 302 alias_column_names = expression.alias_column_names 303 304 if ( 305 isinstance(expression, exp.Unnest) 306 and expression.type 307 and expression.type.is_type(exp.DType.STRUCT) 308 ): 309 selects[name] = { 310 col_def.name: t.cast(t.Union[exp.DataType, exp.DType], col_def.kind) 311 for col_def in expression.type.expressions 312 if isinstance(col_def, exp.ColumnDef) and col_def.kind 313 } 314 else: 315 selects[name] = { 316 alias: column.type for alias, column in zip(alias_column_names, values) 317 } 318 elif isinstance(expression, exp.SetOperation) and len( 319 expression.left.selects 320 ) == len(expression.right.selects): 321 selects[name] = self._get_setop_column_types(expression) 322 elif isinstance(expression, exp.Selectable): 323 selects[name] = {s.alias_or_name: s.type for s in expression.selects if s.type} 324 325 self._scope_selects[scope] = selects 326 327 return self._scope_selects[scope] 328 329 def annotate_scope(self, scope: Scope) -> None: 330 if isinstance(self.schema, MappingSchema): 331 for table_column in scope.table_columns: 332 source = scope.sources.get(table_column.name) 333 334 if isinstance(source, exp.Table): 335 schema = self.schema.find( 336 source, raise_on_missing=False, ensure_data_types=True 337 ) 338 if not isinstance(schema, dict): 339 continue 340 341 struct_type = exp.DataType( 342 this=exp.DType.STRUCT, 343 expressions=[ 344 exp.ColumnDef(this=exp.to_identifier(str(c)), kind=kind) 345 for c, kind in schema.items() 346 ], 347 nested=True, 348 ) 349 self._set_type(table_column, struct_type) 350 elif ( 351 isinstance(source, Scope) 352 and isinstance(source.expression, exp.Query) 353 and ( 354 source.expression.meta.get("query_type") or exp.DType.UNKNOWN.into_expr() 355 ).is_type(exp.DType.STRUCT) 356 ): 357 self._set_type(table_column, source.expression.meta["query_type"]) 358 359 # Iterate through all the expressions of the current scope in post-order, and annotate 360 self._annotate_expression(scope.expression, scope) 361 self._fixup_order_by_aliases(scope) 362 363 if self.dialect.QUERY_RESULTS_ARE_STRUCTS and isinstance(scope.expression, exp.Query): 364 struct_type = exp.DataType( 365 this=exp.DType.STRUCT, 366 expressions=[ 367 exp.ColumnDef( 368 this=exp.to_identifier(select.output_name), 369 kind=select.type.copy() if select.type else None, 370 ) 371 for select in scope.expression.selects 372 ], 373 nested=True, 374 ) 375 376 if not any( 377 cd.kind.is_type(exp.DType.UNKNOWN) for cd in struct_type.expressions if cd.kind 378 ): 379 # We don't use `_set_type` on purpose here. If we annotated the query directly, then 380 # using it in other contexts (e.g., ARRAY(<query>)) could result in incorrect type 381 # annotations, i.e., it shouldn't be interpreted as a STRUCT value. 382 scope.expression.meta["query_type"] = struct_type 383 384 def _annotate_expression( 385 self, 386 expression: exp.Expr, 387 scope: Scope | None = None, 388 ) -> None: 389 stack = [(expression, False)] 390 391 while stack: 392 expr, children_annotated = stack.pop() 393 394 if id(expr) in self._visited or ( 395 not self._overwrite_types and expr.type and not expr.is_type(exp.DType.UNKNOWN) 396 ): 397 continue # We've already inferred the expression's type 398 399 if not children_annotated: 400 stack.append((expr, True)) 401 for child_expr in expr.iter_expressions(): 402 stack.append((child_expr, False)) 403 continue 404 405 if scope and isinstance(expr, exp.Column) and expr.table: 406 source = None 407 source_scope: Scope | None = scope 408 while source_scope and not source: 409 source = source_scope.sources.get(expr.table) 410 if not source: 411 source_scope = source_scope.parent 412 413 if isinstance(source, exp.Table): 414 self._set_type(expr, self.schema.get_column_type(source, expr)) 415 elif source and source_scope: 416 col_type = ( 417 self._get_scope_selects(source_scope).get(expr.table, {}).get(expr.name) 418 ) 419 if col_type: 420 self._set_type(expr, col_type) 421 elif isinstance(source.expression, exp.Unnest): 422 self._set_type(expr, source.expression.type) 423 else: 424 self._set_type(expr, exp.DType.UNKNOWN) 425 else: 426 self._set_type(expr, exp.DType.UNKNOWN) 427 428 if expr.is_type(exp.DType.JSON) and (dot_parts := expr.meta.get("dot_parts")): 429 # JSON dot access is case sensitive across all dialects, so we need to undo the normalization. 430 i = iter(dot_parts) 431 parent = expr.parent 432 while isinstance(parent, exp.Dot): 433 parent.expression.replace(exp.to_identifier(next(i), quoted=True)) 434 parent = parent.parent 435 436 expr.meta.pop("dot_parts", None) 437 438 if expr.type and expr.type.args.get("nullable") is False: 439 expr.meta["nonnull"] = True 440 continue 441 442 spec = self.expression_metadata.get(expr.__class__) 443 444 if spec and (annotator := spec.get("annotator")): 445 annotator(self, expr) 446 elif spec and (returns := spec.get("returns")): 447 self._set_type(expr, returns) 448 else: 449 self._set_type(expr, exp.DType.UNKNOWN) 450 451 def _fixup_order_by_aliases(self, scope: Scope) -> None: 452 query = scope.expression 453 if not isinstance(query, exp.Query): 454 return 455 456 order = query.args.get("order") 457 if not order: 458 return 459 460 # Build alias -> type map from fully-annotated projections (last match wins, 461 # consistent with how _expand_alias_refs handles duplicate aliases). 462 alias_types: dict[str, exp.DataType | exp.DType] = {} 463 for sel in query.selects: 464 if ( 465 isinstance(sel, exp.Alias) 466 and sel.this.type 467 and not sel.this.is_type(exp.DType.UNKNOWN) 468 ): 469 alias_types[sel.alias] = sel.this.type 470 471 if not alias_types: 472 return 473 474 for ordered in order.expressions: 475 alias_cols = [ 476 c for c in ordered.find_all(exp.Column) if not c.table and c.name in alias_types 477 ] 478 for col in alias_cols: 479 self._set_type(col, alias_types[col.name]) 480 481 if alias_cols: 482 for node in ordered.walk(prune=lambda n: isinstance(n, exp.Subquery)): 483 if not isinstance(node, (exp.Column, exp.Literal)): 484 self._visited.discard(id(node)) 485 self._annotate_expression(ordered, scope) 486 487 def _maybe_coerce( 488 self, 489 type1: exp.DataType | exp.DType, 490 type2: exp.DataType | exp.DType, 491 ) -> exp.DataType | exp.DType: 492 """ 493 Returns type2 if type1 can be coerced into it, otherwise type1. 494 495 If either type is parameterized (e.g. DECIMAL(18, 2) contains two parameters), 496 we assume type1 does not coerce into type2, so we also return it in this case. 497 """ 498 if isinstance(type1, exp.DataType): 499 if type1.expressions: 500 return type1 501 type1_value = type1.this 502 else: 503 type1_value = type1 504 505 if isinstance(type2, exp.DataType): 506 if type2.expressions: 507 return type2 508 type2_value = type2.this 509 else: 510 type2_value = type2 511 512 # We propagate the UNKNOWN type upwards if found 513 if exp.DType.UNKNOWN in (type1_value, type2_value): 514 return exp.DType.UNKNOWN 515 516 if type1_value == exp.DType.NULL: 517 return type2_value 518 if type2_value == exp.DType.NULL: 519 return type1_value 520 521 return type2_value if type2_value in self.coerces_to.get(type1_value, {}) else type1_value 522 523 def _get_setop_column_types( 524 self, setop: exp.SetOperation 525 ) -> dict[str, exp.DataType | exp.DType]: 526 """ 527 Computes and returns the coerced column types for a SetOperation. 528 529 This handles UNION, INTERSECT, EXCEPT, etc., coercing types across 530 left and right operands for all projections/columns. 531 532 Args: 533 setop: The SetOperation expression to analyze 534 535 Returns: 536 Dictionary mapping column names to their coerced types 537 """ 538 setop_id = id(setop) 539 if setop_id in self._setop_column_types: 540 return self._setop_column_types[setop_id] 541 542 col_types: dict[str, exp.DataType | exp.DType] = {} 543 544 # Validate that left and right have same number of projections 545 if not ( 546 isinstance(setop, exp.SetOperation) 547 and setop.left.selects 548 and setop.right.selects 549 and len(setop.left.selects) == len(setop.right.selects) 550 ): 551 return col_types 552 553 # Process a chain / sub-tree of set operations 554 for set_op in setop.walk( 555 prune=lambda n: not isinstance(n, (exp.SetOperation, exp.Subquery)) 556 ): 557 if not isinstance(set_op, exp.SetOperation): 558 continue 559 560 if set_op.args.get("by_name"): 561 r_type_by_select = {s.alias_or_name: s.type for s in set_op.right.selects} 562 setop_cols = { 563 s.alias_or_name: self._maybe_coerce( 564 t.cast(exp.DataType, s.type), 565 r_type_by_select.get(s.alias_or_name) or exp.DType.UNKNOWN, 566 ) 567 for s in set_op.left.selects 568 } 569 else: 570 setop_cols = { 571 ls.alias_or_name: self._maybe_coerce( 572 t.cast(exp.DataType, ls.type), t.cast(exp.DataType, rs.type) 573 ) 574 for ls, rs in zip(set_op.left.selects, set_op.right.selects) 575 } 576 577 # Coerce intermediate results with the previously registered types, if they exist 578 for col_name, col_type in setop_cols.items(): 579 col_types[col_name] = self._maybe_coerce( 580 col_type, col_types.get(col_name, exp.DType.NULL) 581 ) 582 583 self._setop_column_types[setop_id] = col_types 584 return col_types 585 586 def _annotate_binary(self, expression: B) -> B: 587 left, right = expression.left, expression.right 588 if not left or not right: 589 expression_sql = expression.sql(self.dialect) 590 logger.warning(f"Failed to annotate badly formed binary expression: {expression_sql}") 591 self._set_type(expression, None) 592 return expression 593 594 left_type, right_type = left.type.this, right.type.this # type: ignore 595 596 # TODO (mypyc): should be isinstance(expression, (exp.Connector, exp.Predicate)) but 597 # mypyc narrows the variable to the first type in a tuple/or isinstance check when 598 # the types are sibling @trait classes, rejecting instances of the second type. 599 if issubclass(type(expression), (exp.Connector, exp.Predicate)): 600 self._set_type(expression, exp.DType.BOOLEAN) 601 elif (left_type, right_type) in self.binary_coercions: 602 self._set_type(expression, self.binary_coercions[(left_type, right_type)](left, right)) 603 else: 604 self._annotate_by_args(expression, left, right) 605 606 if isinstance(expression, exp.Is) or ( 607 left.meta.get("nonnull") is True and right.meta.get("nonnull") is True 608 ): 609 expression.meta["nonnull"] = True 610 611 return expression 612 613 def _annotate_unary(self, expression: E) -> E: 614 if isinstance(expression, exp.Not): 615 self._set_type(expression, exp.DType.BOOLEAN) 616 else: 617 self._set_type(expression, expression.this.type) 618 619 if expression.this.meta.get("nonnull") is True: 620 expression.meta["nonnull"] = True 621 622 return expression 623 624 def _annotate_literal(self, expression: exp.Literal) -> exp.Literal: 625 if expression.is_string: 626 self._set_type(expression, exp.DType.VARCHAR) 627 elif expression.is_int: 628 self._set_type(expression, exp.DType.INT) 629 else: 630 self._set_type(expression, exp.DType.DOUBLE) 631 632 expression.meta["nonnull"] = True 633 634 return expression 635 636 def _annotate_by_args( 637 self, 638 expression: E, 639 *args: str | exp.Expr, 640 promote: bool = False, 641 array: bool = False, 642 ) -> E: 643 literal_type = None 644 non_literal_type = None 645 nested_type = None 646 647 for arg in args: 648 if isinstance(arg, str): 649 expressions = expression.args.get(arg) 650 else: 651 expressions = arg 652 653 for expr in ensure_list(expressions): 654 expr_type = expr.type 655 656 if expr_type.is_type(exp.DType.UNKNOWN): 657 self._set_type(expression, exp.DType.UNKNOWN) 658 return expression 659 660 if nested_type: 661 continue 662 663 # Stop coercing at the first nested data type found 664 if expr_type.args.get("nested"): 665 nested_type = expr_type 666 elif isinstance(expr, exp.Literal): 667 literal_type = self._maybe_coerce(literal_type or expr_type, expr_type) 668 else: 669 non_literal_type = self._maybe_coerce(non_literal_type or expr_type, expr_type) 670 671 result_type = None 672 673 if nested_type: 674 result_type = nested_type 675 elif literal_type and non_literal_type: 676 if self.dialect.PRIORITIZE_NON_LITERAL_TYPES: 677 literal_this_type = ( 678 literal_type.this if isinstance(literal_type, exp.DataType) else literal_type 679 ) 680 non_literal_this_type = ( 681 non_literal_type.this 682 if isinstance(non_literal_type, exp.DataType) 683 else non_literal_type 684 ) 685 if ( 686 literal_this_type in exp.DataType.INTEGER_TYPES 687 and non_literal_this_type in exp.DataType.INTEGER_TYPES 688 ) or ( 689 literal_this_type in exp.DataType.REAL_TYPES 690 and non_literal_this_type in exp.DataType.REAL_TYPES 691 ): 692 result_type = non_literal_type 693 else: 694 result_type = literal_type or non_literal_type or exp.DType.UNKNOWN 695 696 self._set_type( 697 expression, 698 result_type or self._maybe_coerce(non_literal_type, literal_type), # type: ignore 699 ) 700 701 if promote: 702 if expression.type.this in exp.DataType.INTEGER_TYPES: # type: ignore 703 self._set_type(expression, exp.DType.BIGINT) 704 elif expression.type.this in exp.DataType.FLOAT_TYPES: # type: ignore 705 self._set_type(expression, exp.DType.DOUBLE) 706 707 if array: 708 self._set_type( 709 expression, 710 exp.DataType(this=exp.DType.ARRAY, expressions=[expression.type], nested=True), 711 ) 712 713 return expression 714 715 def _annotate_timeunit( 716 self, expression: exp.TimeUnit | exp.DateTrunc 717 ) -> exp.TimeUnit | exp.DateTrunc: 718 if expression.this.type.this in exp.DataType.TEXT_TYPES: 719 datatype = _coerce_date_literal(expression.this, expression.unit) 720 elif expression.this.type.this in exp.DataType.TEMPORAL_TYPES: 721 datatype = _coerce_date(expression.this, expression.unit) 722 else: 723 datatype = exp.DType.UNKNOWN 724 725 self._set_type(expression, datatype) 726 return expression 727 728 def _annotate_bracket(self, expression: exp.Bracket) -> exp.Bracket: 729 bracket_arg = expression.expressions[0] 730 this = expression.this 731 732 if isinstance(bracket_arg, exp.Slice): 733 self._set_type(expression, this.type) 734 elif this.type.is_type(exp.DType.ARRAY): 735 self._set_type(expression, seq_get(this.type.expressions, 0)) 736 elif isinstance(this, (exp.Map, exp.VarMap)) and bracket_arg in this.keys: 737 index = this.keys.index(bracket_arg) 738 value = seq_get(this.values, index) 739 self._set_type(expression, value.type if value else None) 740 else: 741 self._set_type(expression, exp.DType.UNKNOWN) 742 743 return expression 744 745 def _annotate_div(self, expression: exp.Div) -> exp.Div: 746 left_type, right_type = expression.left.type.this, expression.right.type.this # type: ignore 747 748 if ( 749 expression.args.get("typed") 750 and left_type in exp.DataType.INTEGER_TYPES 751 and right_type in exp.DataType.INTEGER_TYPES 752 ): 753 self._set_type(expression, exp.DType.BIGINT) 754 else: 755 self._set_type(expression, self._maybe_coerce(left_type, right_type)) 756 if expression.type and expression.type.this not in exp.DataType.REAL_TYPES: 757 self._set_type(expression, self._maybe_coerce(expression.type, exp.DType.DOUBLE)) 758 759 return expression 760 761 def _annotate_dot(self, expression: exp.Dot) -> exp.Dot: 762 self._set_type(expression, None) 763 764 # Propagate type from qualified UDF calls (e.g., db.my_udf(...)) 765 if isinstance(expression.expression, exp.Anonymous): 766 self._set_type(expression, expression.expression.type) 767 return expression 768 769 this_type = expression.this.type 770 771 if this_type and this_type.is_type(exp.DType.STRUCT): 772 for e in this_type.expressions: 773 if e.name == expression.expression.name: 774 self._set_type(expression, e.kind) 775 break 776 777 return expression 778 779 def _annotate_explode(self, expression: exp.Explode) -> exp.Explode: 780 self._set_type(expression, seq_get(expression.this.type.expressions, 0)) 781 return expression 782 783 def _annotate_unnest(self, expression: exp.Unnest) -> exp.Unnest: 784 child = seq_get(expression.expressions, 0) 785 786 if child and child.is_type(exp.DType.ARRAY): 787 expr_type = seq_get(child.type.expressions, 0) 788 else: 789 expr_type = None 790 791 self._set_type(expression, expr_type) 792 return expression 793 794 def _annotate_subquery(self, expression: exp.Subquery) -> exp.Subquery: 795 # For scalar subqueries (subqueries with a single projection), infer the type 796 # from that single projection. This allows type propagation in cases like: 797 # SELECT (SELECT 1 AS c) AS c 798 query = expression.unnest() 799 800 if isinstance(query, exp.Query): 801 selects = query.selects 802 if len(selects) == 1: 803 self._set_type(expression, selects[0].type) 804 return expression 805 806 self._set_type(expression, exp.DType.UNKNOWN) 807 return expression 808 809 def _annotate_struct_value(self, expression: exp.Expr) -> exp.DataType | None | exp.ColumnDef: 810 # Case: STRUCT(key AS value) 811 this: exp.Expr | None = None 812 kind = expression.type 813 814 if alias := expression.args.get("alias"): 815 this = alias.copy() 816 elif expression.expression: 817 # Case: STRUCT(key = value) or STRUCT(key := value) 818 this = expression.this.copy() 819 kind = expression.expression.type 820 elif isinstance(expression, exp.Column): 821 # Case: STRUCT(c) 822 this = expression.this.copy() 823 824 if kind and kind.is_type(exp.DType.UNKNOWN): 825 return None 826 827 if this: 828 return exp.ColumnDef(this=this, kind=kind) 829 830 return kind 831 832 def _annotate_struct(self, expression: exp.Struct) -> exp.Struct: 833 expressions = [] 834 for expr in expression.expressions: 835 struct_field_type = self._annotate_struct_value(expr) 836 if struct_field_type is None: 837 self._set_type(expression, None) 838 return expression 839 840 expressions.append(struct_field_type) 841 842 self._set_type( 843 expression, 844 exp.DataType(this=exp.DType.STRUCT, expressions=expressions, nested=True), 845 ) 846 return expression 847 848 @t.overload 849 def _annotate_map(self, expression: exp.Map) -> exp.Map: ... 850 851 @t.overload 852 def _annotate_map(self, expression: exp.VarMap) -> exp.VarMap: ... 853 854 def _annotate_map(self, expression): 855 keys = expression.args.get("keys") 856 values = expression.args.get("values") 857 858 map_type = exp.DataType(this=exp.DType.MAP) 859 if isinstance(keys, exp.Array) and isinstance(values, exp.Array): 860 key_type = seq_get(keys.type.expressions, 0) or exp.DType.UNKNOWN 861 value_type = seq_get(values.type.expressions, 0) or exp.DType.UNKNOWN 862 863 if key_type != exp.DType.UNKNOWN and value_type != exp.DType.UNKNOWN: 864 map_type.set("expressions", [key_type, value_type]) 865 map_type.set("nested", True) 866 867 self._set_type(expression, map_type) 868 return expression 869 870 def _annotate_to_map(self, expression: exp.ToMap) -> exp.ToMap: 871 map_type = exp.DataType(this=exp.DType.MAP) 872 arg = expression.this 873 if arg.is_type(exp.DType.STRUCT): 874 for coldef in arg.type.expressions: 875 kind = coldef.kind 876 if kind != exp.DType.UNKNOWN: 877 map_type.set("expressions", [exp.DType.VARCHAR.into_expr(), kind]) 878 map_type.set("nested", True) 879 break 880 881 self._set_type(expression, map_type) 882 return expression 883 884 def _annotate_extract(self, expression: exp.Extract) -> exp.Extract: 885 part = expression.name 886 if part == "TIME": 887 self._set_type(expression, exp.DType.TIME) 888 elif part == "DATE": 889 self._set_type(expression, exp.DType.DATE) 890 elif part in BIGINT_EXTRACT_DATE_PARTS: 891 self._set_type(expression, exp.DType.BIGINT) 892 else: 893 self._set_type(expression, exp.DType.INT) 894 return expression 895 896 def _annotate_by_array_element(self, expression: exp.Expr) -> exp.Expr: 897 array_arg = expression.this 898 if array_arg.type.is_type(exp.DType.ARRAY): 899 element_type = seq_get(array_arg.type.expressions, 0) or exp.DType.UNKNOWN 900 self._set_type(expression, element_type) 901 else: 902 self._set_type(expression, exp.DType.UNKNOWN) 903 904 return expression
TypeAnnotator( schema: sqlglot.schema.Schema, expression_metadata: dict[type[sqlglot.expressions.core.Expr], dict[str, typing.Any]] | None = None, coerces_to: dict[sqlglot.expressions.datatypes.DType, set[sqlglot.expressions.datatypes.DType]] | None = None, binary_coercions: dict[tuple[sqlglot.expressions.datatypes.DType, sqlglot.expressions.datatypes.DType], typing.Callable[[sqlglot.expressions.core.Expr, sqlglot.expressions.core.Expr], typing.Union[sqlglot.expressions.datatypes.DataType, sqlglot.expressions.datatypes.DType, NoneType]]] | None = None, overwrite_types: bool = True)
195 def __init__( 196 self, 197 schema: Schema, 198 expression_metadata: ExprMetadataType | None = None, 199 coerces_to: dict[exp.DType, set[exp.DType]] | None = None, 200 binary_coercions: BinaryCoercions | None = None, 201 overwrite_types: bool = True, 202 ) -> None: 203 self.schema = schema 204 dialect = schema.dialect or Dialect() 205 self.dialect = dialect 206 self.expression_metadata = expression_metadata or dialect.EXPRESSION_METADATA 207 self.coerces_to = coerces_to or dialect.COERCES_TO or self.COERCES_TO 208 self.binary_coercions = binary_coercions or self.BINARY_COERCIONS 209 210 # Caches the ids of annotated sub-Exprs, to ensure we only visit them once 211 self._visited: set[int] = set() 212 213 # Caches NULL-annotated expressions to set them to UNKNOWN after type inference is completed 214 self._null_expressions: dict[int, exp.Expr] = {} 215 216 # Databricks and Spark ≥v3 actually support NULL (i.e., VOID) as a type 217 self._supports_null_type = dialect.SUPPORTS_NULL_TYPE 218 219 # Maps an exp.SetOperation's id (e.g. UNION) to its projection types. This is computed if the 220 # exp.SetOperation is the expression of a scope source, as selecting from it multiple times 221 # would reprocess the entire subtree to coerce the types of its operands' projections 222 self._setop_column_types: dict[int, dict[str, exp.DataType | exp.DType]] = {} 223 224 # When set to False, this enables partial annotation by skipping already-annotated nodes 225 self._overwrite_types = overwrite_types 226 227 # Maps Scope to its corresponding selected sources 228 self._scope_selects: dict[Scope, dict[str, dict[str, t.Any]]] = {}
COERCES_TO: ClassVar[dict[sqlglot.expressions.datatypes.DType, set[sqlglot.expressions.datatypes.DType]]] =
{<DType.TEXT: 'TEXT'>: set(), <DType.NVARCHAR: 'NVARCHAR'>: {<DType.TEXT: 'TEXT'>}, <DType.VARCHAR: 'VARCHAR'>: {<DType.TIME: 'TIME'>, <DType.DATETIME: 'DATETIME'>, <DType.TIMESTAMP: 'TIMESTAMP'>, <DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <DType.DATE: 'DATE'>, <DType.TEXT: 'TEXT'>, <DType.NVARCHAR: 'NVARCHAR'>}, <DType.NCHAR: 'NCHAR'>: {<DType.VARCHAR: 'VARCHAR'>, <DType.TEXT: 'TEXT'>, <DType.NVARCHAR: 'NVARCHAR'>}, <DType.CHAR: 'CHAR'>: {<DType.VARCHAR: 'VARCHAR'>, <DType.NCHAR: 'NCHAR'>, <DType.TEXT: 'TEXT'>, <DType.NVARCHAR: 'NVARCHAR'>}, <DType.DECFLOAT: 'DECFLOAT'>: set(), <DType.DOUBLE: 'DOUBLE'>: {<DType.DECFLOAT: 'DECFLOAT'>}, <DType.FLOAT: 'FLOAT'>: {<DType.DOUBLE: 'DOUBLE'>, <DType.DECFLOAT: 'DECFLOAT'>}, <DType.BIGDECIMAL: 'BIGDECIMAL'>: {<DType.DOUBLE: 'DOUBLE'>, <DType.DECFLOAT: 'DECFLOAT'>, <DType.FLOAT: 'FLOAT'>}, <DType.DECIMAL: 'DECIMAL'>: {<DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.FLOAT: 'FLOAT'>, <DType.DOUBLE: 'DOUBLE'>, <DType.DECFLOAT: 'DECFLOAT'>}, <DType.BIGINT: 'BIGINT'>: {<DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.FLOAT: 'FLOAT'>, <DType.DOUBLE: 'DOUBLE'>, <DType.DECFLOAT: 'DECFLOAT'>, <DType.DECIMAL: 'DECIMAL'>}, <DType.INT: 'INT'>: {<DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.BIGINT: 'BIGINT'>, <DType.FLOAT: 'FLOAT'>, <DType.DOUBLE: 'DOUBLE'>, <DType.DECFLOAT: 'DECFLOAT'>, <DType.DECIMAL: 'DECIMAL'>}, <DType.SMALLINT: 'SMALLINT'>: {<DType.INT: 'INT'>, <DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.BIGINT: 'BIGINT'>, <DType.FLOAT: 'FLOAT'>, <DType.DOUBLE: 'DOUBLE'>, <DType.DECFLOAT: 'DECFLOAT'>, <DType.DECIMAL: 'DECIMAL'>}, <DType.TINYINT: 'TINYINT'>: {<DType.FLOAT: 'FLOAT'>, <DType.INT: 'INT'>, <DType.SMALLINT: 'SMALLINT'>, <DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.BIGINT: 'BIGINT'>, <DType.DOUBLE: 'DOUBLE'>, <DType.DECFLOAT: 'DECFLOAT'>, <DType.DECIMAL: 'DECIMAL'>}, <DType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>: set(), <DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>: {<DType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>}, <DType.TIMESTAMP: 'TIMESTAMP'>: {<DType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>}, <DType.DATETIME: 'DATETIME'>: {<DType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <DType.TIMESTAMP: 'TIMESTAMP'>, <DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>}, <DType.DATE: 'DATE'>: {<DType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <DType.TIMESTAMP: 'TIMESTAMP'>, <DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <DType.DATETIME: 'DATETIME'>}}
BINARY_COERCIONS: ClassVar =
{(<DType.VARCHAR: 'VARCHAR'>, <DType.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INTERVAL: 'INTERVAL'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INTERVAL: 'INTERVAL'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INTERVAL: 'INTERVAL'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INTERVAL: 'INTERVAL'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INTERVAL: 'INTERVAL'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INTERVAL: 'INTERVAL'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.VARCHAR: 'VARCHAR'>, <DType.DECFLOAT: 'DECFLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NCHAR: 'NCHAR'>, <DType.DECFLOAT: 'DECFLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NAME: 'NAME'>, <DType.DECFLOAT: 'DECFLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TEXT: 'TEXT'>, <DType.DECFLOAT: 'DECFLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.NVARCHAR: 'NVARCHAR'>, <DType.DECFLOAT: 'DECFLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.UDECIMAL: 'UDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.UTINYINT: 'UTINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.BIGINT: 'BIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.INT128: 'INT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.UMEDIUMINT: 'UMEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.DECIMAL: 'DECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.MONEY: 'MONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.UDOUBLE: 'UDOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.TINYINT: 'TINYINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.UBIGINT: 'UBIGINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.INT: 'INT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.SMALLINT: 'SMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.DECIMAL256: 'DECIMAL256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.BIGDECIMAL: 'BIGDECIMAL'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.DECIMAL128: 'DECIMAL128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.BIT: 'BIT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.DOUBLE: 'DOUBLE'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.UINT: 'UINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.INT256: 'INT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.SMALLMONEY: 'SMALLMONEY'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.USMALLINT: 'USMALLINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.MEDIUMINT: 'MEDIUMINT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.UINT128: 'UINT128'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.DECIMAL64: 'DECIMAL64'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.FLOAT: 'FLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.DECIMAL32: 'DECIMAL32'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.UINT256: 'UINT256'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.CHAR: 'CHAR'>, <DType.DECFLOAT: 'DECFLOAT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDECIMAL: 'UDECIMAL'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UTINYINT: 'UTINYINT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGINT: 'BIGINT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT128: 'INT128'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UMEDIUMINT: 'UMEDIUMINT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL: 'DECIMAL'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MONEY: 'MONEY'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDOUBLE: 'UDOUBLE'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TINYINT: 'TINYINT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UBIGINT: 'UBIGINT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT: 'INT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLINT: 'SMALLINT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL256: 'DECIMAL256'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL128: 'DECIMAL128'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIT: 'BIT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DOUBLE: 'DOUBLE'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT: 'UINT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT256: 'INT256'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLMONEY: 'SMALLMONEY'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.USMALLINT: 'USMALLINT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MEDIUMINT: 'MEDIUMINT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT128: 'UINT128'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL64: 'DECIMAL64'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.FLOAT: 'FLOAT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL32: 'DECIMAL32'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT256: 'UINT256'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECFLOAT: 'DECFLOAT'>, <DType.VARCHAR: 'VARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDECIMAL: 'UDECIMAL'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UTINYINT: 'UTINYINT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGINT: 'BIGINT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT128: 'INT128'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UMEDIUMINT: 'UMEDIUMINT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL: 'DECIMAL'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MONEY: 'MONEY'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDOUBLE: 'UDOUBLE'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TINYINT: 'TINYINT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UBIGINT: 'UBIGINT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT: 'INT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLINT: 'SMALLINT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL256: 'DECIMAL256'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL128: 'DECIMAL128'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIT: 'BIT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DOUBLE: 'DOUBLE'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT: 'UINT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT256: 'INT256'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLMONEY: 'SMALLMONEY'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.USMALLINT: 'USMALLINT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MEDIUMINT: 'MEDIUMINT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT128: 'UINT128'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL64: 'DECIMAL64'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.FLOAT: 'FLOAT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL32: 'DECIMAL32'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT256: 'UINT256'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECFLOAT: 'DECFLOAT'>, <DType.NCHAR: 'NCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDECIMAL: 'UDECIMAL'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UTINYINT: 'UTINYINT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGINT: 'BIGINT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT128: 'INT128'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UMEDIUMINT: 'UMEDIUMINT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL: 'DECIMAL'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MONEY: 'MONEY'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDOUBLE: 'UDOUBLE'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TINYINT: 'TINYINT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UBIGINT: 'UBIGINT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT: 'INT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLINT: 'SMALLINT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL256: 'DECIMAL256'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL128: 'DECIMAL128'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIT: 'BIT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DOUBLE: 'DOUBLE'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT: 'UINT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT256: 'INT256'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLMONEY: 'SMALLMONEY'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.USMALLINT: 'USMALLINT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MEDIUMINT: 'MEDIUMINT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT128: 'UINT128'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL64: 'DECIMAL64'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.FLOAT: 'FLOAT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL32: 'DECIMAL32'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT256: 'UINT256'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECFLOAT: 'DECFLOAT'>, <DType.NAME: 'NAME'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDECIMAL: 'UDECIMAL'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UTINYINT: 'UTINYINT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGINT: 'BIGINT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT128: 'INT128'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UMEDIUMINT: 'UMEDIUMINT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL: 'DECIMAL'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MONEY: 'MONEY'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDOUBLE: 'UDOUBLE'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TINYINT: 'TINYINT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UBIGINT: 'UBIGINT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT: 'INT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLINT: 'SMALLINT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL256: 'DECIMAL256'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL128: 'DECIMAL128'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIT: 'BIT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DOUBLE: 'DOUBLE'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT: 'UINT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT256: 'INT256'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLMONEY: 'SMALLMONEY'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.USMALLINT: 'USMALLINT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MEDIUMINT: 'MEDIUMINT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT128: 'UINT128'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL64: 'DECIMAL64'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.FLOAT: 'FLOAT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL32: 'DECIMAL32'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT256: 'UINT256'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECFLOAT: 'DECFLOAT'>, <DType.TEXT: 'TEXT'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDECIMAL: 'UDECIMAL'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UTINYINT: 'UTINYINT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGINT: 'BIGINT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT128: 'INT128'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UMEDIUMINT: 'UMEDIUMINT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL: 'DECIMAL'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MONEY: 'MONEY'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDOUBLE: 'UDOUBLE'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TINYINT: 'TINYINT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UBIGINT: 'UBIGINT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT: 'INT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLINT: 'SMALLINT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL256: 'DECIMAL256'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL128: 'DECIMAL128'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIT: 'BIT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DOUBLE: 'DOUBLE'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT: 'UINT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT256: 'INT256'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLMONEY: 'SMALLMONEY'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.USMALLINT: 'USMALLINT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MEDIUMINT: 'MEDIUMINT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT128: 'UINT128'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL64: 'DECIMAL64'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.FLOAT: 'FLOAT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL32: 'DECIMAL32'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT256: 'UINT256'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECFLOAT: 'DECFLOAT'>, <DType.NVARCHAR: 'NVARCHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDECIMAL: 'UDECIMAL'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UTINYINT: 'UTINYINT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGINT: 'BIGINT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT128: 'INT128'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UMEDIUMINT: 'UMEDIUMINT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL: 'DECIMAL'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MONEY: 'MONEY'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UDOUBLE: 'UDOUBLE'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.TINYINT: 'TINYINT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UBIGINT: 'UBIGINT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT: 'INT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLINT: 'SMALLINT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL256: 'DECIMAL256'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIGDECIMAL: 'BIGDECIMAL'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL128: 'DECIMAL128'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.BIT: 'BIT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DOUBLE: 'DOUBLE'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT: 'UINT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.INT256: 'INT256'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.SMALLMONEY: 'SMALLMONEY'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.USMALLINT: 'USMALLINT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.MEDIUMINT: 'MEDIUMINT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT128: 'UINT128'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL64: 'DECIMAL64'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.FLOAT: 'FLOAT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECIMAL32: 'DECIMAL32'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.UINT256: 'UINT256'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DECFLOAT: 'DECFLOAT'>, <DType.CHAR: 'CHAR'>): <function TypeAnnotator.<dictcomp>.<lambda>>, (<DType.DATE: 'DATE'>, <DType.INTERVAL: 'INTERVAL'>): <function TypeAnnotator.<lambda>>, (<DType.INTERVAL: 'INTERVAL'>, <DType.DATE: 'DATE'>): <function TypeAnnotator.<lambda>>}
def
annotate(self, expression: ~E, annotate_scope: bool = True) -> ~E:
261 def annotate(self, expression: E, annotate_scope: bool = True) -> E: 262 # This flag is used to avoid costly scope traversals when we only care about annotating 263 # non-column expressions (partial type inference), e.g., when simplifying in the optimizer 264 if annotate_scope: 265 for scope in traverse_scope(expression): 266 self.annotate_scope(scope) 267 268 # This takes care of non-traversable expressions 269 self._annotate_expression(expression) 270 271 # Replace NULL type with the default type of the targeted dialect, since the former is not an actual type; 272 # it is mostly used to aid type coercion, e.g. in query set operations. 273 # TODO (mypyc): uses list() + _set_type instead of direct expr.type = ... because 274 # mypyc's property setter bypass rejects DType, and _set_type modifies the dict. 275 for expr in list(self._null_expressions.values()): 276 self._set_type(expr, self.dialect.DEFAULT_NULL_TYPE) 277 278 return expression
329 def annotate_scope(self, scope: Scope) -> None: 330 if isinstance(self.schema, MappingSchema): 331 for table_column in scope.table_columns: 332 source = scope.sources.get(table_column.name) 333 334 if isinstance(source, exp.Table): 335 schema = self.schema.find( 336 source, raise_on_missing=False, ensure_data_types=True 337 ) 338 if not isinstance(schema, dict): 339 continue 340 341 struct_type = exp.DataType( 342 this=exp.DType.STRUCT, 343 expressions=[ 344 exp.ColumnDef(this=exp.to_identifier(str(c)), kind=kind) 345 for c, kind in schema.items() 346 ], 347 nested=True, 348 ) 349 self._set_type(table_column, struct_type) 350 elif ( 351 isinstance(source, Scope) 352 and isinstance(source.expression, exp.Query) 353 and ( 354 source.expression.meta.get("query_type") or exp.DType.UNKNOWN.into_expr() 355 ).is_type(exp.DType.STRUCT) 356 ): 357 self._set_type(table_column, source.expression.meta["query_type"]) 358 359 # Iterate through all the expressions of the current scope in post-order, and annotate 360 self._annotate_expression(scope.expression, scope) 361 self._fixup_order_by_aliases(scope) 362 363 if self.dialect.QUERY_RESULTS_ARE_STRUCTS and isinstance(scope.expression, exp.Query): 364 struct_type = exp.DataType( 365 this=exp.DType.STRUCT, 366 expressions=[ 367 exp.ColumnDef( 368 this=exp.to_identifier(select.output_name), 369 kind=select.type.copy() if select.type else None, 370 ) 371 for select in scope.expression.selects 372 ], 373 nested=True, 374 ) 375 376 if not any( 377 cd.kind.is_type(exp.DType.UNKNOWN) for cd in struct_type.expressions if cd.kind 378 ): 379 # We don't use `_set_type` on purpose here. If we annotated the query directly, then 380 # using it in other contexts (e.g., ARRAY(<query>)) could result in incorrect type 381 # annotations, i.e., it shouldn't be interpreted as a STRUCT value. 382 scope.expression.meta["query_type"] = struct_type