sqlglot.generators.bigquery
1from __future__ import annotations 2 3import logging 4import re 5import typing as t 6 7from sqlglot import exp, generator, transforms 8from sqlglot.dialects.dialect import ( 9 arg_max_or_min_no_count, 10 date_add_interval_sql, 11 datestrtodate_sql, 12 filter_array_using_unnest, 13 generate_series_sql, 14 if_sql, 15 inline_array_unless_query, 16 max_or_greatest, 17 min_or_least, 18 no_ilike_sql, 19 regexp_replace_sql, 20 rename_func, 21 sha256_sql, 22 timestrtotime_sql, 23 ts_or_ds_add_cast, 24 unit_to_var, 25 strposition_sql, 26 groupconcat_sql, 27 sha2_digest_sql, 28) 29from sqlglot.generator import unsupported_args 30from sqlglot.helper import seq_get 31 32logger = logging.getLogger("sqlglot") 33 34JSON_EXTRACT_TYPE = t.Union[exp.JSONExtract, exp.JSONExtractScalar, exp.JSONExtractArray] 35 36DQUOTES_ESCAPING_JSON_FUNCTIONS = ("JSON_QUERY", "JSON_VALUE", "JSON_QUERY_ARRAY") 37 38 39def _derived_table_values_to_unnest(self: BigQueryGenerator, expression: exp.Values) -> str: 40 if not expression.find_ancestor(exp.From, exp.Join): 41 return self.values_sql(expression) 42 43 structs = [] 44 alias = expression.args.get("alias") 45 for tup in expression.find_all(exp.Tuple): 46 field_aliases = ( 47 alias.columns 48 if alias and alias.columns 49 else (f"_c{i}" for i in range(len(tup.expressions))) 50 ) 51 expressions = [ 52 exp.PropertyEQ(this=exp.to_identifier(name), expression=fld) 53 for name, fld in zip(field_aliases, tup.expressions) 54 ] 55 structs.append(exp.Struct(expressions=expressions)) 56 57 # Due to `UNNEST_COLUMN_ONLY`, it is expected that the table alias be contained in the columns expression 58 alias_name_only = exp.TableAlias(columns=[alias.this]) if alias else None 59 return self.unnest_sql( 60 exp.Unnest(expressions=[exp.array(*structs, copy=False)], alias=alias_name_only) 61 ) 62 63 64def _returnsproperty_sql(self: BigQueryGenerator, expression: exp.ReturnsProperty) -> str: 65 this = expression.this 66 if isinstance(this, exp.Schema): 67 this = f"{self.sql(this, 'this')} <{self.expressions(this)}>" 68 else: 69 this = self.sql(this) 70 return f"RETURNS {this}" 71 72 73def _create_sql(self: BigQueryGenerator, expression: exp.Create) -> str: 74 returns = expression.find(exp.ReturnsProperty) 75 if expression.kind == "FUNCTION" and returns and returns.args.get("is_table"): 76 expression.set("kind", "TABLE FUNCTION") 77 78 if isinstance(expression.expression, (exp.Subquery, exp.Literal)): 79 expression.set("expression", expression.expression.this) 80 81 return self.create_sql(expression) 82 83 84# https://issuetracker.google.com/issues/162294746 85# workaround for bigquery bug when grouping by an expression and then ordering 86# WITH x AS (SELECT 1 y) 87# SELECT y + 1 z 88# FROM x 89# GROUP BY x + 1 90# ORDER by z 91def _alias_ordered_group(expression: exp.Expr) -> exp.Expr: 92 if isinstance(expression, exp.Select): 93 group = expression.args.get("group") 94 order = expression.args.get("order") 95 96 if group and order: 97 aliases = { 98 select.this: select.args["alias"] 99 for select in expression.selects 100 if isinstance(select, exp.Alias) 101 } 102 103 for grouped in group.expressions: 104 if grouped.is_int: 105 continue 106 alias = aliases.get(grouped) 107 if alias: 108 grouped.replace(exp.column(alias)) 109 110 return expression 111 112 113def _pushdown_cte_column_names(expression: exp.Expr) -> exp.Expr: 114 """BigQuery doesn't allow column names when defining a CTE, so we try to push them down.""" 115 if isinstance(expression, exp.CTE) and expression.alias_column_names: 116 cte_query = expression.this 117 118 if cte_query.is_star: 119 logger.warning( 120 "Can't push down CTE column names for star queries. Run the query through" 121 " the optimizer or use 'qualify' to expand the star projections first." 122 ) 123 return expression 124 125 column_names = expression.alias_column_names 126 expression.args["alias"].set("columns", None) 127 128 for name, select in zip(column_names, cte_query.selects): 129 to_replace = select 130 131 if isinstance(select, exp.Alias): 132 select = select.this 133 134 # Inner aliases are shadowed by the CTE column names 135 to_replace.replace(exp.alias_(select, name)) 136 137 return expression 138 139 140def _array_contains_sql(self: BigQueryGenerator, expression: exp.ArrayContains) -> str: 141 return self.sql( 142 exp.Exists( 143 this=exp.select("1") 144 .from_(exp.Unnest(expressions=[expression.left]).as_("_unnest", table=["_col"])) 145 .where(exp.column("_col").eq(expression.right)) 146 ) 147 ) 148 149 150def _ts_or_ds_add_sql(self: BigQueryGenerator, expression: exp.TsOrDsAdd) -> str: 151 return date_add_interval_sql("DATE", "ADD")(self, ts_or_ds_add_cast(expression)) 152 153 154def _ts_or_ds_diff_sql(self: BigQueryGenerator, expression: exp.TsOrDsDiff) -> str: 155 expression.this.replace(exp.cast(expression.this, exp.DType.TIMESTAMP)) 156 expression.expression.replace(exp.cast(expression.expression, exp.DType.TIMESTAMP)) 157 unit = unit_to_var(expression) 158 return self.func("DATE_DIFF", expression.this, expression.expression, unit) 159 160 161def _unix_to_time_sql(self: BigQueryGenerator, expression: exp.UnixToTime) -> str: 162 scale = expression.args.get("scale") 163 timestamp = expression.this 164 165 if scale in (None, exp.UnixToTime.SECONDS): 166 return self.func("TIMESTAMP_SECONDS", timestamp) 167 if scale == exp.UnixToTime.MILLIS: 168 return self.func("TIMESTAMP_MILLIS", timestamp) 169 if scale == exp.UnixToTime.MICROS: 170 return self.func("TIMESTAMP_MICROS", timestamp) 171 172 unix_seconds = exp.cast( 173 exp.Div(this=timestamp, expression=exp.func("POW", 10, scale)), exp.DType.BIGINT 174 ) 175 return self.func("TIMESTAMP_SECONDS", unix_seconds) 176 177 178def _str_to_datetime_sql(self: BigQueryGenerator, expression: exp.StrToDate | exp.StrToTime) -> str: 179 this = self.sql(expression, "this") 180 dtype = "DATE" if isinstance(expression, exp.StrToDate) else "TIMESTAMP" 181 182 if expression.args.get("safe"): 183 fmt = self.format_time( 184 expression, 185 self.dialect.INVERSE_FORMAT_MAPPING, 186 self.dialect.INVERSE_FORMAT_TRIE, 187 ) 188 return f"SAFE_CAST({this} AS {dtype} FORMAT {fmt})" 189 190 fmt = self.format_time(expression) 191 return self.func(f"PARSE_{dtype}", fmt, this, expression.args.get("zone")) 192 193 194@unsupported_args("ins_cost", "del_cost", "sub_cost") 195def _levenshtein_sql(self: BigQueryGenerator, expression: exp.Levenshtein) -> str: 196 max_dist = expression.args.get("max_dist") 197 if max_dist: 198 max_dist = exp.Kwarg(this=exp.var("max_distance"), expression=max_dist) 199 200 return self.func("EDIT_DISTANCE", expression.this, expression.expression, max_dist) 201 202 203def _json_extract_sql(self: BigQueryGenerator, expression: JSON_EXTRACT_TYPE) -> str: 204 name = (expression._meta and expression.meta.get("name")) or expression.sql_name() 205 upper = name.upper() 206 207 dquote_escaping = upper in DQUOTES_ESCAPING_JSON_FUNCTIONS 208 209 if dquote_escaping: 210 self._quote_json_path_key_using_brackets = False 211 212 sql = rename_func(upper)(self, expression) 213 214 if dquote_escaping: 215 self._quote_json_path_key_using_brackets = True 216 217 return sql 218 219 220class BigQueryGenerator(generator.Generator): 221 TRY_SUPPORTED = False 222 SUPPORTS_UESCAPE = False 223 SUPPORTS_DECODE_CASE = False 224 INTERVAL_ALLOWS_PLURAL_FORM = False 225 JOIN_HINTS = False 226 QUERY_HINTS = False 227 TABLE_HINTS = False 228 LIMIT_FETCH = "LIMIT" 229 RENAME_TABLE_WITH_DB = False 230 NVL2_SUPPORTED = False 231 UNNEST_WITH_ORDINALITY = False 232 COLLATE_IS_FUNC = True 233 LIMIT_ONLY_LITERALS = True 234 SUPPORTS_TABLE_ALIAS_COLUMNS = False 235 UNPIVOT_ALIASES_ARE_IDENTIFIERS = False 236 JSON_KEY_VALUE_PAIR_SEP = "," 237 NULL_ORDERING_SUPPORTED: bool | None = False 238 IGNORE_NULLS_IN_FUNC = True 239 JSON_PATH_SINGLE_QUOTE_ESCAPE = True 240 CAN_IMPLEMENT_ARRAY_ANY = True 241 SUPPORTS_TO_NUMBER = False 242 NAMED_PLACEHOLDER_TOKEN = "@" 243 HEX_FUNC = "TO_HEX" 244 WITH_PROPERTIES_PREFIX = "OPTIONS" 245 SUPPORTS_EXPLODING_PROJECTIONS = False 246 EXCEPT_INTERSECT_SUPPORT_ALL_CLAUSE = False 247 SUPPORTS_UNIX_SECONDS = True 248 DECLARE_DEFAULT_ASSIGNMENT = "DEFAULT" 249 250 SAFE_JSON_PATH_KEY_RE = re.compile(r"^[\-\w]*$") 251 252 WINDOW_FUNCS_WITH_NULL_ORDERING = ( 253 exp.CumeDist, 254 exp.DenseRank, 255 exp.FirstValue, 256 exp.Lag, 257 exp.LastValue, 258 exp.Lead, 259 exp.NthValue, 260 exp.Ntile, 261 exp.PercentRank, 262 exp.Rank, 263 exp.RowNumber, 264 ) 265 266 TS_OR_DS_TYPES = ( 267 exp.TsOrDsToDatetime, 268 exp.TsOrDsToTimestamp, 269 exp.TsOrDsToTime, 270 exp.TsOrDsToDate, 271 ) 272 273 TRANSFORMS = { 274 **generator.Generator.TRANSFORMS, 275 exp.AIEmbed: rename_func("EMBED"), 276 exp.AIGenerate: rename_func("GENERATE"), 277 exp.AISimilarity: rename_func("SIMILARITY"), 278 exp.ApproxTopK: rename_func("APPROX_TOP_COUNT"), 279 exp.ApproxDistinct: rename_func("APPROX_COUNT_DISTINCT"), 280 exp.ArgMax: arg_max_or_min_no_count("MAX_BY"), 281 exp.ArgMin: arg_max_or_min_no_count("MIN_BY"), 282 exp.Array: inline_array_unless_query, 283 exp.ArrayContains: _array_contains_sql, 284 exp.ArrayFilter: filter_array_using_unnest, 285 exp.ArrayRemove: filter_array_using_unnest, 286 exp.BitwiseAndAgg: rename_func("BIT_AND"), 287 exp.BitwiseOrAgg: rename_func("BIT_OR"), 288 exp.BitwiseXorAgg: rename_func("BIT_XOR"), 289 exp.BitwiseCount: rename_func("BIT_COUNT"), 290 exp.ByteLength: rename_func("BYTE_LENGTH"), 291 exp.Cast: transforms.preprocess([transforms.remove_precision_parameterized_types]), 292 exp.CollateProperty: lambda self, e: ( 293 f"DEFAULT COLLATE {self.sql(e, 'this')}" 294 if e.args.get("default") 295 else f"COLLATE {self.sql(e, 'this')}" 296 ), 297 exp.Commit: lambda *_: "COMMIT TRANSACTION", 298 exp.CountIf: rename_func("COUNTIF"), 299 exp.Create: _create_sql, 300 exp.CTE: transforms.preprocess([_pushdown_cte_column_names]), 301 exp.DateAdd: date_add_interval_sql("DATE", "ADD"), 302 exp.DateDiff: lambda self, e: self.func("DATE_DIFF", e.this, e.expression, unit_to_var(e)), 303 exp.DateFromParts: rename_func("DATE"), 304 exp.DateStrToDate: datestrtodate_sql, 305 exp.DateSub: date_add_interval_sql("DATE", "SUB"), 306 exp.DatetimeAdd: date_add_interval_sql("DATETIME", "ADD"), 307 exp.DatetimeSub: date_add_interval_sql("DATETIME", "SUB"), 308 exp.DateFromUnixDate: rename_func("DATE_FROM_UNIX_DATE"), 309 exp.FromTimeZone: lambda self, e: self.func( 310 "DATETIME", self.func("TIMESTAMP", e.this, e.args.get("zone")), "'UTC'" 311 ), 312 exp.GenerateSeries: generate_series_sql("GENERATE_ARRAY"), 313 exp.GroupConcat: lambda self, e: groupconcat_sql( 314 self, e, func_name="STRING_AGG", within_group=False, sep=None 315 ), 316 exp.Hex: lambda self, e: self.func("UPPER", self.func("TO_HEX", self.sql(e, "this"))), 317 exp.HexString: lambda self, e: self.hexstring_sql(e, binary_function_repr="FROM_HEX"), 318 exp.If: if_sql(false_value="NULL"), 319 exp.ILike: no_ilike_sql, 320 exp.IntDiv: rename_func("DIV"), 321 exp.Int64: rename_func("INT64"), 322 exp.JSONBool: rename_func("BOOL"), 323 exp.JSONExtract: _json_extract_sql, 324 exp.JSONExtractArray: _json_extract_sql, 325 exp.JSONExtractScalar: _json_extract_sql, 326 exp.JSONFormat: lambda self, e: self.func( 327 "TO_JSON" if e.args.get("to_json") else "TO_JSON_STRING", 328 e.this, 329 e.args.get("options"), 330 ), 331 exp.JSONKeysAtDepth: rename_func("JSON_KEYS"), 332 exp.JSONValueArray: rename_func("JSON_VALUE_ARRAY"), 333 exp.Levenshtein: _levenshtein_sql, 334 exp.Max: max_or_greatest, 335 exp.MD5: lambda self, e: self.func("TO_HEX", self.func("MD5", e.this)), 336 exp.MD5Digest: rename_func("MD5"), 337 exp.Min: min_or_least, 338 exp.Normalize: lambda self, e: self.func( 339 "NORMALIZE_AND_CASEFOLD" if e.args.get("is_casefold") else "NORMALIZE", 340 e.this, 341 e.args.get("form"), 342 ), 343 exp.PartitionedByProperty: lambda self, e: f"PARTITION BY {self.sql(e, 'this')}", 344 exp.RegexpExtract: lambda self, e: self.func( 345 "REGEXP_EXTRACT", 346 e.this, 347 e.expression, 348 e.args.get("position"), 349 e.args.get("occurrence"), 350 ), 351 exp.RegexpExtractAll: lambda self, e: self.func("REGEXP_EXTRACT_ALL", e.this, e.expression), 352 exp.RegexpReplace: regexp_replace_sql, 353 exp.RegexpLike: rename_func("REGEXP_CONTAINS"), 354 exp.ReturnsProperty: _returnsproperty_sql, 355 exp.Rollback: lambda *_: "ROLLBACK TRANSACTION", 356 exp.ParseTime: lambda self, e: self.func("PARSE_TIME", self.format_time(e), e.this), 357 exp.ParseDatetime: lambda self, e: self.func("PARSE_DATETIME", self.format_time(e), e.this), 358 exp.Select: transforms.preprocess( 359 [ 360 transforms.explode_projection_to_unnest(), 361 transforms.unqualify_unnest, 362 transforms.eliminate_distinct_on, 363 _alias_ordered_group, 364 transforms.eliminate_semi_and_anti_joins, 365 ] 366 ), 367 exp.SHA: rename_func("SHA1"), 368 exp.SHA2: sha256_sql, 369 exp.SHA1Digest: rename_func("SHA1"), 370 exp.SHA2Digest: sha2_digest_sql, 371 exp.StabilityProperty: lambda self, e: ( 372 "DETERMINISTIC" if e.name == "IMMUTABLE" else "NOT DETERMINISTIC" 373 ), 374 exp.String: rename_func("STRING"), 375 exp.StrPosition: lambda self, e: strposition_sql( 376 self, e, func_name="INSTR", supports_position=True, supports_occurrence=True 377 ), 378 exp.StrToDate: _str_to_datetime_sql, 379 exp.StrToTime: _str_to_datetime_sql, 380 exp.SessionUser: lambda *_: "SESSION_USER()", 381 exp.TimeAdd: date_add_interval_sql("TIME", "ADD"), 382 exp.TimeFromParts: rename_func("TIME"), 383 exp.TimestampFromParts: rename_func("DATETIME"), 384 exp.TimeSub: date_add_interval_sql("TIME", "SUB"), 385 exp.TimestampAdd: date_add_interval_sql("TIMESTAMP", "ADD"), 386 exp.TimestampDiff: rename_func("TIMESTAMP_DIFF"), 387 exp.TimestampSub: date_add_interval_sql("TIMESTAMP", "SUB"), 388 exp.TimeStrToTime: timestrtotime_sql, 389 exp.Transaction: lambda *_: "BEGIN TRANSACTION", 390 exp.TsOrDsAdd: _ts_or_ds_add_sql, 391 exp.TsOrDsDiff: _ts_or_ds_diff_sql, 392 exp.TsOrDsToTime: rename_func("TIME"), 393 exp.TsOrDsToDatetime: rename_func("DATETIME"), 394 exp.TsOrDsToTimestamp: rename_func("TIMESTAMP"), 395 exp.Unhex: rename_func("FROM_HEX"), 396 exp.UnixDate: rename_func("UNIX_DATE"), 397 exp.UnixToTime: _unix_to_time_sql, 398 exp.Uuid: lambda *_: "GENERATE_UUID()", 399 exp.Values: _derived_table_values_to_unnest, 400 exp.VariancePop: rename_func("VAR_POP"), 401 exp.SafeDivide: rename_func("SAFE_DIVIDE"), 402 } 403 404 SUPPORTED_JSON_PATH_PARTS = { 405 exp.JSONPathKey, 406 exp.JSONPathRoot, 407 exp.JSONPathSubscript, 408 } 409 410 TYPE_MAPPING = { 411 **generator.Generator.TYPE_MAPPING, 412 exp.DType.BIGDECIMAL: "BIGNUMERIC", 413 exp.DType.BIGINT: "INT64", 414 exp.DType.BINARY: "BYTES", 415 exp.DType.BLOB: "BYTES", 416 exp.DType.BOOLEAN: "BOOL", 417 exp.DType.CHAR: "STRING", 418 exp.DType.DECIMAL: "NUMERIC", 419 exp.DType.DOUBLE: "FLOAT64", 420 exp.DType.FLOAT: "FLOAT64", 421 exp.DType.INT: "INT64", 422 exp.DType.NCHAR: "STRING", 423 exp.DType.NVARCHAR: "STRING", 424 exp.DType.SMALLINT: "INT64", 425 exp.DType.TEXT: "STRING", 426 exp.DType.TIMESTAMP: "DATETIME", 427 exp.DType.TIMESTAMPNTZ: "DATETIME", 428 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 429 exp.DType.TIMESTAMPLTZ: "TIMESTAMP", 430 exp.DType.TINYINT: "INT64", 431 exp.DType.ROWVERSION: "BYTES", 432 exp.DType.UUID: "STRING", 433 exp.DType.VARBINARY: "BYTES", 434 exp.DType.VARCHAR: "STRING", 435 exp.DType.VARIANT: "ANY TYPE", 436 } 437 438 PROPERTIES_LOCATION = { 439 **generator.Generator.PROPERTIES_LOCATION, 440 exp.PartitionedByProperty: exp.Properties.Location.POST_SCHEMA, 441 exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED, 442 } 443 444 # WINDOW comes after QUALIFY 445 # https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#window_clause 446 # BigQuery requires QUALIFY before WINDOW 447 AFTER_HAVING_MODIFIER_TRANSFORMS = { 448 "qualify": generator.AFTER_HAVING_MODIFIER_TRANSFORMS["qualify"], 449 "windows": generator.AFTER_HAVING_MODIFIER_TRANSFORMS["windows"], 450 } 451 452 # from: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#reserved_keywords 453 RESERVED_KEYWORDS = { 454 "all", 455 "and", 456 "any", 457 "array", 458 "as", 459 "asc", 460 "assert_rows_modified", 461 "at", 462 "between", 463 "by", 464 "case", 465 "cast", 466 "collate", 467 "contains", 468 "create", 469 "cross", 470 "cube", 471 "current", 472 "default", 473 "define", 474 "desc", 475 "distinct", 476 "else", 477 "end", 478 "enum", 479 "escape", 480 "except", 481 "exclude", 482 "exists", 483 "extract", 484 "false", 485 "fetch", 486 "following", 487 "for", 488 "from", 489 "full", 490 "group", 491 "grouping", 492 "groups", 493 "hash", 494 "having", 495 "if", 496 "ignore", 497 "in", 498 "inner", 499 "intersect", 500 "interval", 501 "into", 502 "is", 503 "join", 504 "lateral", 505 "left", 506 "like", 507 "limit", 508 "lookup", 509 "merge", 510 "natural", 511 "new", 512 "no", 513 "not", 514 "null", 515 "nulls", 516 "of", 517 "on", 518 "or", 519 "order", 520 "outer", 521 "over", 522 "partition", 523 "preceding", 524 "proto", 525 "qualify", 526 "range", 527 "recursive", 528 "respect", 529 "right", 530 "rollup", 531 "rows", 532 "select", 533 "set", 534 "some", 535 "struct", 536 "tablesample", 537 "then", 538 "to", 539 "treat", 540 "true", 541 "unbounded", 542 "union", 543 "unnest", 544 "using", 545 "when", 546 "where", 547 "window", 548 "with", 549 "within", 550 } 551 552 def datetrunc_sql(self, expression: exp.DateTrunc) -> str: 553 unit = expression.unit 554 unit_sql = unit.name if unit.is_string else self.sql(unit) 555 return self.func("DATE_TRUNC", expression.this, unit_sql, expression.args.get("zone")) 556 557 def mod_sql(self, expression: exp.Mod) -> str: 558 this = expression.this 559 expr = expression.expression 560 return self.func( 561 "MOD", 562 this.unnest() if isinstance(this, exp.Paren) else this, 563 expr.unnest() if isinstance(expr, exp.Paren) else expr, 564 ) 565 566 def column_parts(self, expression: exp.Column) -> str: 567 if expression.meta.get("quoted_column"): 568 # If a column reference is of the form `dataset.table`.name, we need 569 # to preserve the quoted table path, otherwise the reference breaks 570 table_parts = ".".join(p.name for p in expression.parts[:-1]) 571 table_path = self.sql(exp.Identifier(this=table_parts, quoted=True)) 572 return f"{table_path}.{self.sql(expression, 'this')}" 573 574 return super().column_parts(expression) 575 576 def table_parts(self, expression: exp.Table) -> str: 577 # Depending on the context, `x.y` may not resolve to the same data source as `x`.`y`, so 578 # we need to make sure the correct quoting is used in each case. 579 # 580 # For example, if there is a CTE x that clashes with a schema name, then the former will 581 # return the table y in that schema, whereas the latter will return the CTE's y column: 582 # 583 # - WITH x AS (SELECT [1, 2] AS y) SELECT * FROM x, `x.y` -> cross join 584 # - WITH x AS (SELECT [1, 2] AS y) SELECT * FROM x, `x`.`y` -> implicit unnest 585 if expression.meta.get("quoted_table"): 586 table_parts = ".".join(p.name for p in expression.parts) 587 return self.sql(exp.Identifier(this=table_parts, quoted=True)) 588 589 return super().table_parts(expression) 590 591 def timetostr_sql(self, expression: exp.TimeToStr) -> str: 592 this = expression.this 593 if isinstance(this, exp.TsOrDsToDatetime): 594 func_name = "FORMAT_DATETIME" 595 elif isinstance(this, exp.TsOrDsToTimestamp): 596 func_name = "FORMAT_TIMESTAMP" 597 elif isinstance(this, exp.TsOrDsToTime): 598 func_name = "FORMAT_TIME" 599 else: 600 func_name = "FORMAT_DATE" 601 602 time_expr = this if isinstance(this, self.TS_OR_DS_TYPES) else expression 603 return self.func( 604 func_name, self.format_time(expression), time_expr.this, expression.args.get("zone") 605 ) 606 607 def eq_sql(self, expression: exp.EQ) -> str: 608 # Operands of = cannot be NULL in BigQuery 609 if isinstance(expression.left, exp.Null) or isinstance(expression.right, exp.Null): 610 if not isinstance(expression.parent, exp.Update): 611 return "NULL" 612 613 return self.binary(expression, "=") 614 615 def attimezone_sql(self, expression: exp.AtTimeZone) -> str: 616 parent = expression.parent 617 618 # BigQuery allows CAST(.. AS {STRING|TIMESTAMP} [FORMAT <fmt> [AT TIME ZONE <tz>]]). 619 # Only the TIMESTAMP one should use the below conversion, when AT TIME ZONE is included. 620 if not isinstance(parent, exp.Cast) or not parent.to.is_type("text"): 621 return self.func( 622 "TIMESTAMP", self.func("DATETIME", expression.this, expression.args.get("zone")) 623 ) 624 625 return super().attimezone_sql(expression) 626 627 def trycast_sql(self, expression: exp.TryCast) -> str: 628 return self.cast_sql(expression, safe_prefix="SAFE_") 629 630 def bracket_sql(self, expression: exp.Bracket) -> str: 631 this = expression.this 632 expressions = expression.expressions 633 634 if len(expressions) == 1 and this and this.is_type(exp.DType.STRUCT): 635 arg = expressions[0] 636 if arg.type is None: 637 from sqlglot.optimizer.annotate_types import annotate_types 638 639 arg = annotate_types(arg, dialect=self.dialect) 640 641 if arg.type and arg.type.this in exp.DataType.TEXT_TYPES: 642 # BQ doesn't support bracket syntax with string values for structs 643 return f"{self.sql(this)}.{arg.name}" 644 645 expressions_sql = self.expressions(expression, flat=True) 646 offset = expression.args.get("offset") 647 648 if offset == 0: 649 expressions_sql = f"OFFSET({expressions_sql})" 650 elif offset == 1: 651 expressions_sql = f"ORDINAL({expressions_sql})" 652 elif offset is not None: 653 self.unsupported(f"Unsupported array offset: {offset}") 654 655 if expression.args.get("safe"): 656 expressions_sql = f"SAFE_{expressions_sql}" 657 658 return f"{self.sql(this)}[{expressions_sql}]" 659 660 def in_unnest_op(self, expression: exp.Unnest) -> str: 661 return self.sql(expression) 662 663 def version_sql(self, expression: exp.Version) -> str: 664 if expression.name == "TIMESTAMP": 665 expression.set("this", "SYSTEM_TIME") 666 return super().version_sql(expression) 667 668 def contains_sql(self, expression: exp.Contains) -> str: 669 this = expression.this 670 expr = expression.expression 671 672 if isinstance(this, exp.Lower) and isinstance(expr, exp.Lower): 673 this = this.this 674 expr = expr.this 675 676 return self.func("CONTAINS_SUBSTR", this, expr, expression.args.get("json_scope")) 677 678 def cast_sql(self, expression: exp.Cast, safe_prefix: str | None = None) -> str: 679 this = expression.this 680 681 # This ensures that inline type-annotated ARRAY literals like ARRAY<INT64>[1, 2, 3] 682 # are roundtripped unaffected. The inner check excludes ARRAY(SELECT ...) expressions, 683 # because they aren't literals and so the above syntax is invalid BigQuery. 684 if isinstance(this, exp.Array): 685 elem = seq_get(this.expressions, 0) 686 if not (elem and elem.find(exp.Query)): 687 return f"{self.sql(expression, 'to')}{self.sql(this)}" 688 689 return super().cast_sql(expression, safe_prefix=safe_prefix)
logger =
<Logger sqlglot (WARNING)>
JSON_EXTRACT_TYPE =
typing.Union[sqlglot.expressions.json.JSONExtract, sqlglot.expressions.json.JSONExtractScalar, sqlglot.expressions.json.JSONExtractArray]
DQUOTES_ESCAPING_JSON_FUNCTIONS =
('JSON_QUERY', 'JSON_VALUE', 'JSON_QUERY_ARRAY')
221class BigQueryGenerator(generator.Generator): 222 TRY_SUPPORTED = False 223 SUPPORTS_UESCAPE = False 224 SUPPORTS_DECODE_CASE = False 225 INTERVAL_ALLOWS_PLURAL_FORM = False 226 JOIN_HINTS = False 227 QUERY_HINTS = False 228 TABLE_HINTS = False 229 LIMIT_FETCH = "LIMIT" 230 RENAME_TABLE_WITH_DB = False 231 NVL2_SUPPORTED = False 232 UNNEST_WITH_ORDINALITY = False 233 COLLATE_IS_FUNC = True 234 LIMIT_ONLY_LITERALS = True 235 SUPPORTS_TABLE_ALIAS_COLUMNS = False 236 UNPIVOT_ALIASES_ARE_IDENTIFIERS = False 237 JSON_KEY_VALUE_PAIR_SEP = "," 238 NULL_ORDERING_SUPPORTED: bool | None = False 239 IGNORE_NULLS_IN_FUNC = True 240 JSON_PATH_SINGLE_QUOTE_ESCAPE = True 241 CAN_IMPLEMENT_ARRAY_ANY = True 242 SUPPORTS_TO_NUMBER = False 243 NAMED_PLACEHOLDER_TOKEN = "@" 244 HEX_FUNC = "TO_HEX" 245 WITH_PROPERTIES_PREFIX = "OPTIONS" 246 SUPPORTS_EXPLODING_PROJECTIONS = False 247 EXCEPT_INTERSECT_SUPPORT_ALL_CLAUSE = False 248 SUPPORTS_UNIX_SECONDS = True 249 DECLARE_DEFAULT_ASSIGNMENT = "DEFAULT" 250 251 SAFE_JSON_PATH_KEY_RE = re.compile(r"^[\-\w]*$") 252 253 WINDOW_FUNCS_WITH_NULL_ORDERING = ( 254 exp.CumeDist, 255 exp.DenseRank, 256 exp.FirstValue, 257 exp.Lag, 258 exp.LastValue, 259 exp.Lead, 260 exp.NthValue, 261 exp.Ntile, 262 exp.PercentRank, 263 exp.Rank, 264 exp.RowNumber, 265 ) 266 267 TS_OR_DS_TYPES = ( 268 exp.TsOrDsToDatetime, 269 exp.TsOrDsToTimestamp, 270 exp.TsOrDsToTime, 271 exp.TsOrDsToDate, 272 ) 273 274 TRANSFORMS = { 275 **generator.Generator.TRANSFORMS, 276 exp.AIEmbed: rename_func("EMBED"), 277 exp.AIGenerate: rename_func("GENERATE"), 278 exp.AISimilarity: rename_func("SIMILARITY"), 279 exp.ApproxTopK: rename_func("APPROX_TOP_COUNT"), 280 exp.ApproxDistinct: rename_func("APPROX_COUNT_DISTINCT"), 281 exp.ArgMax: arg_max_or_min_no_count("MAX_BY"), 282 exp.ArgMin: arg_max_or_min_no_count("MIN_BY"), 283 exp.Array: inline_array_unless_query, 284 exp.ArrayContains: _array_contains_sql, 285 exp.ArrayFilter: filter_array_using_unnest, 286 exp.ArrayRemove: filter_array_using_unnest, 287 exp.BitwiseAndAgg: rename_func("BIT_AND"), 288 exp.BitwiseOrAgg: rename_func("BIT_OR"), 289 exp.BitwiseXorAgg: rename_func("BIT_XOR"), 290 exp.BitwiseCount: rename_func("BIT_COUNT"), 291 exp.ByteLength: rename_func("BYTE_LENGTH"), 292 exp.Cast: transforms.preprocess([transforms.remove_precision_parameterized_types]), 293 exp.CollateProperty: lambda self, e: ( 294 f"DEFAULT COLLATE {self.sql(e, 'this')}" 295 if e.args.get("default") 296 else f"COLLATE {self.sql(e, 'this')}" 297 ), 298 exp.Commit: lambda *_: "COMMIT TRANSACTION", 299 exp.CountIf: rename_func("COUNTIF"), 300 exp.Create: _create_sql, 301 exp.CTE: transforms.preprocess([_pushdown_cte_column_names]), 302 exp.DateAdd: date_add_interval_sql("DATE", "ADD"), 303 exp.DateDiff: lambda self, e: self.func("DATE_DIFF", e.this, e.expression, unit_to_var(e)), 304 exp.DateFromParts: rename_func("DATE"), 305 exp.DateStrToDate: datestrtodate_sql, 306 exp.DateSub: date_add_interval_sql("DATE", "SUB"), 307 exp.DatetimeAdd: date_add_interval_sql("DATETIME", "ADD"), 308 exp.DatetimeSub: date_add_interval_sql("DATETIME", "SUB"), 309 exp.DateFromUnixDate: rename_func("DATE_FROM_UNIX_DATE"), 310 exp.FromTimeZone: lambda self, e: self.func( 311 "DATETIME", self.func("TIMESTAMP", e.this, e.args.get("zone")), "'UTC'" 312 ), 313 exp.GenerateSeries: generate_series_sql("GENERATE_ARRAY"), 314 exp.GroupConcat: lambda self, e: groupconcat_sql( 315 self, e, func_name="STRING_AGG", within_group=False, sep=None 316 ), 317 exp.Hex: lambda self, e: self.func("UPPER", self.func("TO_HEX", self.sql(e, "this"))), 318 exp.HexString: lambda self, e: self.hexstring_sql(e, binary_function_repr="FROM_HEX"), 319 exp.If: if_sql(false_value="NULL"), 320 exp.ILike: no_ilike_sql, 321 exp.IntDiv: rename_func("DIV"), 322 exp.Int64: rename_func("INT64"), 323 exp.JSONBool: rename_func("BOOL"), 324 exp.JSONExtract: _json_extract_sql, 325 exp.JSONExtractArray: _json_extract_sql, 326 exp.JSONExtractScalar: _json_extract_sql, 327 exp.JSONFormat: lambda self, e: self.func( 328 "TO_JSON" if e.args.get("to_json") else "TO_JSON_STRING", 329 e.this, 330 e.args.get("options"), 331 ), 332 exp.JSONKeysAtDepth: rename_func("JSON_KEYS"), 333 exp.JSONValueArray: rename_func("JSON_VALUE_ARRAY"), 334 exp.Levenshtein: _levenshtein_sql, 335 exp.Max: max_or_greatest, 336 exp.MD5: lambda self, e: self.func("TO_HEX", self.func("MD5", e.this)), 337 exp.MD5Digest: rename_func("MD5"), 338 exp.Min: min_or_least, 339 exp.Normalize: lambda self, e: self.func( 340 "NORMALIZE_AND_CASEFOLD" if e.args.get("is_casefold") else "NORMALIZE", 341 e.this, 342 e.args.get("form"), 343 ), 344 exp.PartitionedByProperty: lambda self, e: f"PARTITION BY {self.sql(e, 'this')}", 345 exp.RegexpExtract: lambda self, e: self.func( 346 "REGEXP_EXTRACT", 347 e.this, 348 e.expression, 349 e.args.get("position"), 350 e.args.get("occurrence"), 351 ), 352 exp.RegexpExtractAll: lambda self, e: self.func("REGEXP_EXTRACT_ALL", e.this, e.expression), 353 exp.RegexpReplace: regexp_replace_sql, 354 exp.RegexpLike: rename_func("REGEXP_CONTAINS"), 355 exp.ReturnsProperty: _returnsproperty_sql, 356 exp.Rollback: lambda *_: "ROLLBACK TRANSACTION", 357 exp.ParseTime: lambda self, e: self.func("PARSE_TIME", self.format_time(e), e.this), 358 exp.ParseDatetime: lambda self, e: self.func("PARSE_DATETIME", self.format_time(e), e.this), 359 exp.Select: transforms.preprocess( 360 [ 361 transforms.explode_projection_to_unnest(), 362 transforms.unqualify_unnest, 363 transforms.eliminate_distinct_on, 364 _alias_ordered_group, 365 transforms.eliminate_semi_and_anti_joins, 366 ] 367 ), 368 exp.SHA: rename_func("SHA1"), 369 exp.SHA2: sha256_sql, 370 exp.SHA1Digest: rename_func("SHA1"), 371 exp.SHA2Digest: sha2_digest_sql, 372 exp.StabilityProperty: lambda self, e: ( 373 "DETERMINISTIC" if e.name == "IMMUTABLE" else "NOT DETERMINISTIC" 374 ), 375 exp.String: rename_func("STRING"), 376 exp.StrPosition: lambda self, e: strposition_sql( 377 self, e, func_name="INSTR", supports_position=True, supports_occurrence=True 378 ), 379 exp.StrToDate: _str_to_datetime_sql, 380 exp.StrToTime: _str_to_datetime_sql, 381 exp.SessionUser: lambda *_: "SESSION_USER()", 382 exp.TimeAdd: date_add_interval_sql("TIME", "ADD"), 383 exp.TimeFromParts: rename_func("TIME"), 384 exp.TimestampFromParts: rename_func("DATETIME"), 385 exp.TimeSub: date_add_interval_sql("TIME", "SUB"), 386 exp.TimestampAdd: date_add_interval_sql("TIMESTAMP", "ADD"), 387 exp.TimestampDiff: rename_func("TIMESTAMP_DIFF"), 388 exp.TimestampSub: date_add_interval_sql("TIMESTAMP", "SUB"), 389 exp.TimeStrToTime: timestrtotime_sql, 390 exp.Transaction: lambda *_: "BEGIN TRANSACTION", 391 exp.TsOrDsAdd: _ts_or_ds_add_sql, 392 exp.TsOrDsDiff: _ts_or_ds_diff_sql, 393 exp.TsOrDsToTime: rename_func("TIME"), 394 exp.TsOrDsToDatetime: rename_func("DATETIME"), 395 exp.TsOrDsToTimestamp: rename_func("TIMESTAMP"), 396 exp.Unhex: rename_func("FROM_HEX"), 397 exp.UnixDate: rename_func("UNIX_DATE"), 398 exp.UnixToTime: _unix_to_time_sql, 399 exp.Uuid: lambda *_: "GENERATE_UUID()", 400 exp.Values: _derived_table_values_to_unnest, 401 exp.VariancePop: rename_func("VAR_POP"), 402 exp.SafeDivide: rename_func("SAFE_DIVIDE"), 403 } 404 405 SUPPORTED_JSON_PATH_PARTS = { 406 exp.JSONPathKey, 407 exp.JSONPathRoot, 408 exp.JSONPathSubscript, 409 } 410 411 TYPE_MAPPING = { 412 **generator.Generator.TYPE_MAPPING, 413 exp.DType.BIGDECIMAL: "BIGNUMERIC", 414 exp.DType.BIGINT: "INT64", 415 exp.DType.BINARY: "BYTES", 416 exp.DType.BLOB: "BYTES", 417 exp.DType.BOOLEAN: "BOOL", 418 exp.DType.CHAR: "STRING", 419 exp.DType.DECIMAL: "NUMERIC", 420 exp.DType.DOUBLE: "FLOAT64", 421 exp.DType.FLOAT: "FLOAT64", 422 exp.DType.INT: "INT64", 423 exp.DType.NCHAR: "STRING", 424 exp.DType.NVARCHAR: "STRING", 425 exp.DType.SMALLINT: "INT64", 426 exp.DType.TEXT: "STRING", 427 exp.DType.TIMESTAMP: "DATETIME", 428 exp.DType.TIMESTAMPNTZ: "DATETIME", 429 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 430 exp.DType.TIMESTAMPLTZ: "TIMESTAMP", 431 exp.DType.TINYINT: "INT64", 432 exp.DType.ROWVERSION: "BYTES", 433 exp.DType.UUID: "STRING", 434 exp.DType.VARBINARY: "BYTES", 435 exp.DType.VARCHAR: "STRING", 436 exp.DType.VARIANT: "ANY TYPE", 437 } 438 439 PROPERTIES_LOCATION = { 440 **generator.Generator.PROPERTIES_LOCATION, 441 exp.PartitionedByProperty: exp.Properties.Location.POST_SCHEMA, 442 exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED, 443 } 444 445 # WINDOW comes after QUALIFY 446 # https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#window_clause 447 # BigQuery requires QUALIFY before WINDOW 448 AFTER_HAVING_MODIFIER_TRANSFORMS = { 449 "qualify": generator.AFTER_HAVING_MODIFIER_TRANSFORMS["qualify"], 450 "windows": generator.AFTER_HAVING_MODIFIER_TRANSFORMS["windows"], 451 } 452 453 # from: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#reserved_keywords 454 RESERVED_KEYWORDS = { 455 "all", 456 "and", 457 "any", 458 "array", 459 "as", 460 "asc", 461 "assert_rows_modified", 462 "at", 463 "between", 464 "by", 465 "case", 466 "cast", 467 "collate", 468 "contains", 469 "create", 470 "cross", 471 "cube", 472 "current", 473 "default", 474 "define", 475 "desc", 476 "distinct", 477 "else", 478 "end", 479 "enum", 480 "escape", 481 "except", 482 "exclude", 483 "exists", 484 "extract", 485 "false", 486 "fetch", 487 "following", 488 "for", 489 "from", 490 "full", 491 "group", 492 "grouping", 493 "groups", 494 "hash", 495 "having", 496 "if", 497 "ignore", 498 "in", 499 "inner", 500 "intersect", 501 "interval", 502 "into", 503 "is", 504 "join", 505 "lateral", 506 "left", 507 "like", 508 "limit", 509 "lookup", 510 "merge", 511 "natural", 512 "new", 513 "no", 514 "not", 515 "null", 516 "nulls", 517 "of", 518 "on", 519 "or", 520 "order", 521 "outer", 522 "over", 523 "partition", 524 "preceding", 525 "proto", 526 "qualify", 527 "range", 528 "recursive", 529 "respect", 530 "right", 531 "rollup", 532 "rows", 533 "select", 534 "set", 535 "some", 536 "struct", 537 "tablesample", 538 "then", 539 "to", 540 "treat", 541 "true", 542 "unbounded", 543 "union", 544 "unnest", 545 "using", 546 "when", 547 "where", 548 "window", 549 "with", 550 "within", 551 } 552 553 def datetrunc_sql(self, expression: exp.DateTrunc) -> str: 554 unit = expression.unit 555 unit_sql = unit.name if unit.is_string else self.sql(unit) 556 return self.func("DATE_TRUNC", expression.this, unit_sql, expression.args.get("zone")) 557 558 def mod_sql(self, expression: exp.Mod) -> str: 559 this = expression.this 560 expr = expression.expression 561 return self.func( 562 "MOD", 563 this.unnest() if isinstance(this, exp.Paren) else this, 564 expr.unnest() if isinstance(expr, exp.Paren) else expr, 565 ) 566 567 def column_parts(self, expression: exp.Column) -> str: 568 if expression.meta.get("quoted_column"): 569 # If a column reference is of the form `dataset.table`.name, we need 570 # to preserve the quoted table path, otherwise the reference breaks 571 table_parts = ".".join(p.name for p in expression.parts[:-1]) 572 table_path = self.sql(exp.Identifier(this=table_parts, quoted=True)) 573 return f"{table_path}.{self.sql(expression, 'this')}" 574 575 return super().column_parts(expression) 576 577 def table_parts(self, expression: exp.Table) -> str: 578 # Depending on the context, `x.y` may not resolve to the same data source as `x`.`y`, so 579 # we need to make sure the correct quoting is used in each case. 580 # 581 # For example, if there is a CTE x that clashes with a schema name, then the former will 582 # return the table y in that schema, whereas the latter will return the CTE's y column: 583 # 584 # - WITH x AS (SELECT [1, 2] AS y) SELECT * FROM x, `x.y` -> cross join 585 # - WITH x AS (SELECT [1, 2] AS y) SELECT * FROM x, `x`.`y` -> implicit unnest 586 if expression.meta.get("quoted_table"): 587 table_parts = ".".join(p.name for p in expression.parts) 588 return self.sql(exp.Identifier(this=table_parts, quoted=True)) 589 590 return super().table_parts(expression) 591 592 def timetostr_sql(self, expression: exp.TimeToStr) -> str: 593 this = expression.this 594 if isinstance(this, exp.TsOrDsToDatetime): 595 func_name = "FORMAT_DATETIME" 596 elif isinstance(this, exp.TsOrDsToTimestamp): 597 func_name = "FORMAT_TIMESTAMP" 598 elif isinstance(this, exp.TsOrDsToTime): 599 func_name = "FORMAT_TIME" 600 else: 601 func_name = "FORMAT_DATE" 602 603 time_expr = this if isinstance(this, self.TS_OR_DS_TYPES) else expression 604 return self.func( 605 func_name, self.format_time(expression), time_expr.this, expression.args.get("zone") 606 ) 607 608 def eq_sql(self, expression: exp.EQ) -> str: 609 # Operands of = cannot be NULL in BigQuery 610 if isinstance(expression.left, exp.Null) or isinstance(expression.right, exp.Null): 611 if not isinstance(expression.parent, exp.Update): 612 return "NULL" 613 614 return self.binary(expression, "=") 615 616 def attimezone_sql(self, expression: exp.AtTimeZone) -> str: 617 parent = expression.parent 618 619 # BigQuery allows CAST(.. AS {STRING|TIMESTAMP} [FORMAT <fmt> [AT TIME ZONE <tz>]]). 620 # Only the TIMESTAMP one should use the below conversion, when AT TIME ZONE is included. 621 if not isinstance(parent, exp.Cast) or not parent.to.is_type("text"): 622 return self.func( 623 "TIMESTAMP", self.func("DATETIME", expression.this, expression.args.get("zone")) 624 ) 625 626 return super().attimezone_sql(expression) 627 628 def trycast_sql(self, expression: exp.TryCast) -> str: 629 return self.cast_sql(expression, safe_prefix="SAFE_") 630 631 def bracket_sql(self, expression: exp.Bracket) -> str: 632 this = expression.this 633 expressions = expression.expressions 634 635 if len(expressions) == 1 and this and this.is_type(exp.DType.STRUCT): 636 arg = expressions[0] 637 if arg.type is None: 638 from sqlglot.optimizer.annotate_types import annotate_types 639 640 arg = annotate_types(arg, dialect=self.dialect) 641 642 if arg.type and arg.type.this in exp.DataType.TEXT_TYPES: 643 # BQ doesn't support bracket syntax with string values for structs 644 return f"{self.sql(this)}.{arg.name}" 645 646 expressions_sql = self.expressions(expression, flat=True) 647 offset = expression.args.get("offset") 648 649 if offset == 0: 650 expressions_sql = f"OFFSET({expressions_sql})" 651 elif offset == 1: 652 expressions_sql = f"ORDINAL({expressions_sql})" 653 elif offset is not None: 654 self.unsupported(f"Unsupported array offset: {offset}") 655 656 if expression.args.get("safe"): 657 expressions_sql = f"SAFE_{expressions_sql}" 658 659 return f"{self.sql(this)}[{expressions_sql}]" 660 661 def in_unnest_op(self, expression: exp.Unnest) -> str: 662 return self.sql(expression) 663 664 def version_sql(self, expression: exp.Version) -> str: 665 if expression.name == "TIMESTAMP": 666 expression.set("this", "SYSTEM_TIME") 667 return super().version_sql(expression) 668 669 def contains_sql(self, expression: exp.Contains) -> str: 670 this = expression.this 671 expr = expression.expression 672 673 if isinstance(this, exp.Lower) and isinstance(expr, exp.Lower): 674 this = this.this 675 expr = expr.this 676 677 return self.func("CONTAINS_SUBSTR", this, expr, expression.args.get("json_scope")) 678 679 def cast_sql(self, expression: exp.Cast, safe_prefix: str | None = None) -> str: 680 this = expression.this 681 682 # This ensures that inline type-annotated ARRAY literals like ARRAY<INT64>[1, 2, 3] 683 # are roundtripped unaffected. The inner check excludes ARRAY(SELECT ...) expressions, 684 # because they aren't literals and so the above syntax is invalid BigQuery. 685 if isinstance(this, exp.Array): 686 elem = seq_get(this.expressions, 0) 687 if not (elem and elem.find(exp.Query)): 688 return f"{self.sql(expression, 'to')}{self.sql(this)}" 689 690 return super().cast_sql(expression, safe_prefix=safe_prefix)
Generator converts a given syntax tree to the corresponding SQL string.
Arguments:
- pretty: Whether to format the produced SQL string. Default: False.
- identify: Determines when an identifier should be quoted. Possible values are: False (default): Never quote, except in cases where it's mandatory by the dialect. True: Always quote except for specials cases. 'safe': Only quote identifiers that are case insensitive.
- normalize: Whether to normalize identifiers to lowercase. Default: False.
- pad: The pad size in a formatted string. For example, this affects the indentation of a projection in a query, relative to its nesting level. Default: 2.
- indent: The indentation size in a formatted string. For example, this affects the
indentation of subqueries and filters under a
WHEREclause. Default: 2. - normalize_functions: How to normalize function names. Possible values are: "upper" or True (default): Convert names to uppercase. "lower": Convert names to lowercase. False: Disables function name normalization.
- unsupported_level: Determines the generator's behavior when it encounters unsupported expressions. Default ErrorLevel.WARN.
- max_unsupported: Maximum number of unsupported messages to include in a raised UnsupportedError. This is only relevant if unsupported_level is ErrorLevel.RAISE. Default: 3
- leading_comma: Whether the comma is leading or trailing in select expressions. This is only relevant when generating in pretty mode. Default: False
- max_text_width: The max number of characters in a segment before creating new lines in pretty mode. The default is on the smaller end because the length only represents a segment and not the true line length. Default: 80
- comments: Whether to preserve comments in the output SQL code. Default: True
WINDOW_FUNCS_WITH_NULL_ORDERING =
(<class 'sqlglot.expressions.aggregate.CumeDist'>, <class 'sqlglot.expressions.aggregate.DenseRank'>, <class 'sqlglot.expressions.aggregate.FirstValue'>, <class 'sqlglot.expressions.aggregate.Lag'>, <class 'sqlglot.expressions.aggregate.LastValue'>, <class 'sqlglot.expressions.aggregate.Lead'>, <class 'sqlglot.expressions.aggregate.NthValue'>, <class 'sqlglot.expressions.aggregate.Ntile'>, <class 'sqlglot.expressions.aggregate.PercentRank'>, <class 'sqlglot.expressions.aggregate.Rank'>, <class 'sqlglot.expressions.aggregate.RowNumber'>)
TS_OR_DS_TYPES =
(<class 'sqlglot.expressions.temporal.TsOrDsToDatetime'>, <class 'sqlglot.expressions.temporal.TsOrDsToTimestamp'>, <class 'sqlglot.expressions.temporal.TsOrDsToTime'>, <class 'sqlglot.expressions.temporal.TsOrDsToDate'>)
TRANSFORMS =
{<class 'sqlglot.expressions.query.JSONPathKey'>: <function <lambda>>, <class 'sqlglot.expressions.query.JSONPathRoot'>: <function <lambda>>, <class 'sqlglot.expressions.query.JSONPathSubscript'>: <function <lambda>>, <class 'sqlglot.expressions.core.Adjacent'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.AllowedValuesProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.AnalyzeColumns'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.AnalyzeWith'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.ArrayContainsAll'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.ArrayOverlaps'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.AssumeColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.AutoRefreshProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.BackupProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CaseSpecificColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.math.Ceil'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CharacterSetColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CharacterSetProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.ClusteredColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CollateColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CommentColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.ConnectByRoot'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.string.ConvertToCharset'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CopyGrantsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CredentialsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.CurrentCatalog'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.SessionUser'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.constraints.DateFormatColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.DefaultColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ApiProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ApplicationProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CatalogProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ComputeProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.DatabaseProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.DynamicProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.EmptyProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.EncodeColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.EndStatement'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.EnviromentProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.HandlerProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ParameterStyleProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.EphemeralColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.ExcludeColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ExecuteAsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Except'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ExternalProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.math.Floor'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Get'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.GlobalProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.HeapProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.HybridProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.IcebergProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.InheritsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.InlineLengthColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.InputModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Intersect'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.datatypes.IntervalSpan'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.Int64'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.json.JSONBContainsAnyTopKeys'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONBContainsAllTopKeys'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONBDeleteAtPath'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONObject'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONObjectAgg'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.LanguageProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.LocationProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.LogProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.MaskingProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.MaterializedProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.NetFunc'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.NetworkProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.NonClusteredColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.NoPrimaryIndexProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.NotForReplicationColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.OnCommitProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.OnProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.OnUpdateColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.Operator'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.OutputModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.ExtendsLeft'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.ExtendsRight'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.PathColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.PartitionedByBucket'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.PartitionByTruncate'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.PivotAny'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.PositionalColumn'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.ProjectionPolicyColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.InvisibleColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.ZeroFillColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Put'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.RemoteWithConnectionModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ReturnsProperty'>: <function _returnsproperty_sql>, <class 'sqlglot.expressions.properties.RowAccessProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.SafeFunc'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SampleProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SecureProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SecurityIntegrationProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SetConfigProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SetProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SettingsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SharingProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SqlReadWriteProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SqlSecurityProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.StabilityProperty'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.query.Stream'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.StreamingTableProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.StrictProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ddl.SwapTable'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.TableColumn'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.Tags'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.TemporaryProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.TitleColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.ToMap'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ToTableProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.TransformModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.TransientProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.VirtualProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ddl.TriggerExecute'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Union'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.UnloggedProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.UsingTemplateProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.UsingData'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.UppercaseColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.temporal.UtcDate'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.temporal.UtcTime'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.temporal.UtcTimestamp'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Variadic'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.VarMap'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ViewAttributeProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.VolatileProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.WithJournalTableProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.WithProcedureOptions'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.WithSchemaBindingProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.WithOperator'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ForceProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.AIEmbed'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.functions.AIGenerate'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.functions.AISimilarity'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.aggregate.ApproxTopK'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.core.ApproxDistinct'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.aggregate.ArgMax'>: <function arg_max_or_min_no_count.<locals>._arg_max_or_min_sql>, <class 'sqlglot.expressions.aggregate.ArgMin'>: <function arg_max_or_min_no_count.<locals>._arg_max_or_min_sql>, <class 'sqlglot.expressions.array.Array'>: <function inline_array_unless_query>, <class 'sqlglot.expressions.array.ArrayContains'>: <function _array_contains_sql>, <class 'sqlglot.expressions.array.ArrayFilter'>: <function filter_array_using_unnest>, <class 'sqlglot.expressions.array.ArrayRemove'>: <function filter_array_using_unnest>, <class 'sqlglot.expressions.math.BitwiseAndAgg'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.math.BitwiseOrAgg'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.math.BitwiseXorAgg'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.math.BitwiseCount'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.string.ByteLength'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.functions.Cast'>: <function preprocess.<locals>._to_sql>, <class 'sqlglot.expressions.properties.CollateProperty'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.ddl.Commit'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.aggregate.CountIf'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.ddl.Create'>: <function _create_sql>, <class 'sqlglot.expressions.query.CTE'>: <function preprocess.<locals>._to_sql>, <class 'sqlglot.expressions.temporal.DateAdd'>: <function date_add_interval_sql.<locals>.func>, <class 'sqlglot.expressions.temporal.DateDiff'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.DateFromParts'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.DateStrToDate'>: <function datestrtodate_sql>, <class 'sqlglot.expressions.temporal.DateSub'>: <function date_add_interval_sql.<locals>.func>, <class 'sqlglot.expressions.temporal.DatetimeAdd'>: <function date_add_interval_sql.<locals>.func>, <class 'sqlglot.expressions.temporal.DatetimeSub'>: <function date_add_interval_sql.<locals>.func>, <class 'sqlglot.expressions.temporal.DateFromUnixDate'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.core.FromTimeZone'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.array.GenerateSeries'>: <function generate_series_sql.<locals>._generate_series_sql>, <class 'sqlglot.expressions.aggregate.GroupConcat'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.string.Hex'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.query.HexString'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.functions.If'>: <function if_sql.<locals>._if_sql>, <class 'sqlglot.expressions.core.ILike'>: <function no_ilike_sql>, <class 'sqlglot.expressions.core.IntDiv'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.json.JSONBool'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.json.JSONExtract'>: <function _json_extract_sql>, <class 'sqlglot.expressions.json.JSONExtractArray'>: <function _json_extract_sql>, <class 'sqlglot.expressions.json.JSONExtractScalar'>: <function _json_extract_sql>, <class 'sqlglot.expressions.json.JSONFormat'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.json.JSONKeysAtDepth'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.query.JSONValueArray'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.string.Levenshtein'>: <function _levenshtein_sql>, <class 'sqlglot.expressions.aggregate.Max'>: <function max_or_greatest>, <class 'sqlglot.expressions.string.MD5'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.string.MD5Digest'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.aggregate.Min'>: <function min_or_least>, <class 'sqlglot.expressions.string.Normalize'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.properties.PartitionedByProperty'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.string.RegexpExtract'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.string.RegexpExtractAll'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.string.RegexpReplace'>: <function regexp_replace_sql>, <class 'sqlglot.expressions.core.RegexpLike'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.ddl.Rollback'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.ParseTime'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.ParseDatetime'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.query.Select'>: <function preprocess.<locals>._to_sql>, <class 'sqlglot.expressions.string.SHA'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.string.SHA2'>: <function sha256_sql>, <class 'sqlglot.expressions.string.SHA1Digest'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.string.SHA2Digest'>: <function sha2_digest_sql>, <class 'sqlglot.expressions.string.String'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.string.StrPosition'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.StrToDate'>: <function _str_to_datetime_sql>, <class 'sqlglot.expressions.temporal.StrToTime'>: <function _str_to_datetime_sql>, <class 'sqlglot.expressions.temporal.TimeAdd'>: <function date_add_interval_sql.<locals>.func>, <class 'sqlglot.expressions.temporal.TimeFromParts'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.TimestampFromParts'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.TimeSub'>: <function date_add_interval_sql.<locals>.func>, <class 'sqlglot.expressions.temporal.TimestampAdd'>: <function date_add_interval_sql.<locals>.func>, <class 'sqlglot.expressions.temporal.TimestampDiff'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.TimestampSub'>: <function date_add_interval_sql.<locals>.func>, <class 'sqlglot.expressions.temporal.TimeStrToTime'>: <function timestrtotime_sql>, <class 'sqlglot.expressions.ddl.Transaction'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.TsOrDsAdd'>: <function _ts_or_ds_add_sql>, <class 'sqlglot.expressions.temporal.TsOrDsDiff'>: <function _ts_or_ds_diff_sql>, <class 'sqlglot.expressions.temporal.TsOrDsToTime'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.TsOrDsToDatetime'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.TsOrDsToTimestamp'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.string.Unhex'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.UnixDate'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.UnixToTime'>: <function _unix_to_time_sql>, <class 'sqlglot.expressions.functions.Uuid'>: <function BigQueryGenerator.<lambda>>, <class 'sqlglot.expressions.query.Values'>: <function _derived_table_values_to_unnest>, <class 'sqlglot.expressions.aggregate.VariancePop'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.math.SafeDivide'>: <function rename_func.<locals>.<lambda>>}
SUPPORTED_JSON_PATH_PARTS =
{<class 'sqlglot.expressions.query.JSONPathRoot'>, <class 'sqlglot.expressions.query.JSONPathSubscript'>, <class 'sqlglot.expressions.query.JSONPathKey'>}
TYPE_MAPPING =
{<DType.DATETIME2: 'DATETIME2'>: 'TIMESTAMP', <DType.NCHAR: 'NCHAR'>: 'STRING', <DType.NVARCHAR: 'NVARCHAR'>: 'STRING', <DType.MEDIUMTEXT: 'MEDIUMTEXT'>: 'TEXT', <DType.LONGTEXT: 'LONGTEXT'>: 'TEXT', <DType.TINYTEXT: 'TINYTEXT'>: 'TEXT', <DType.BLOB: 'BLOB'>: 'BYTES', <DType.MEDIUMBLOB: 'MEDIUMBLOB'>: 'BLOB', <DType.LONGBLOB: 'LONGBLOB'>: 'BLOB', <DType.TINYBLOB: 'TINYBLOB'>: 'BLOB', <DType.INET: 'INET'>: 'INET', <DType.ROWVERSION: 'ROWVERSION'>: 'BYTES', <DType.SMALLDATETIME: 'SMALLDATETIME'>: 'TIMESTAMP', <DType.BIGDECIMAL: 'BIGDECIMAL'>: 'BIGNUMERIC', <DType.BIGINT: 'BIGINT'>: 'INT64', <DType.BINARY: 'BINARY'>: 'BYTES', <DType.BOOLEAN: 'BOOLEAN'>: 'BOOL', <DType.CHAR: 'CHAR'>: 'STRING', <DType.DECIMAL: 'DECIMAL'>: 'NUMERIC', <DType.DOUBLE: 'DOUBLE'>: 'FLOAT64', <DType.FLOAT: 'FLOAT'>: 'FLOAT64', <DType.INT: 'INT'>: 'INT64', <DType.SMALLINT: 'SMALLINT'>: 'INT64', <DType.TEXT: 'TEXT'>: 'STRING', <DType.TIMESTAMP: 'TIMESTAMP'>: 'DATETIME', <DType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>: 'DATETIME', <DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>: 'TIMESTAMP', <DType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>: 'TIMESTAMP', <DType.TINYINT: 'TINYINT'>: 'INT64', <DType.UUID: 'UUID'>: 'STRING', <DType.VARBINARY: 'VARBINARY'>: 'BYTES', <DType.VARCHAR: 'VARCHAR'>: 'STRING', <DType.VARIANT: 'VARIANT'>: 'ANY TYPE'}
PROPERTIES_LOCATION =
{<class 'sqlglot.expressions.properties.AllowedValuesProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.AlgorithmProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.ApiProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.ApplicationProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.AutoIncrementProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.AutoRefreshProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.BackupProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.BlockCompressionProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.CatalogProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.CharacterSetProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ChecksumProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.CollateProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ComputeProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.CopyGrantsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.query.Cluster'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ClusteredByProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DistributedByProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DuplicateKeyProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DataBlocksizeProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.DatabaseProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.DataDeletionProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DefinerProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.DictRange'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DictProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DynamicProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.DistKeyProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DistStyleProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.EmptyProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.EncodeProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.EngineProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.EnviromentProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.HandlerProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ParameterStyleProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ExecuteAsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ExternalProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.FallbackProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.FileFormatProperty'>: <PropertiesLocation.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.properties.FreespaceProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.GlobalProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.HeapProperty'>: <PropertiesLocation.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.properties.HybridProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.InheritsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.IcebergProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.IncludeProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.InputModelProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.IsolatedLoadingProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.JournalProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.LanguageProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.LikeProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.LocationProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.LockProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.LockingProperty'>: <PropertiesLocation.POST_ALIAS: 'POST_ALIAS'>, <class 'sqlglot.expressions.properties.LogProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.MaskingProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.MaterializedProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.MergeBlockRatioProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.ModuleProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.NetworkProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.NoPrimaryIndexProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.OnProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.OnCommitProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.query.Order'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.OutputModelProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.PartitionedByProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.PartitionedOfProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.constraints.PrimaryKey'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.Property'>: <PropertiesLocation.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.properties.RefreshTriggerProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.RemoteWithConnectionModelProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ReturnsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.RollupProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.RowAccessProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.RowFormatProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.RowFormatDelimitedProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.RowFormatSerdeProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SampleProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SchemaCommentProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SecureProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.SecurityIntegrationProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.SerdeProperties'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.ddl.Set'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SettingsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SetProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.SetConfigProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SharingProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.ddl.SequenceProperties'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.ddl.TriggerProperties'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.SortKeyProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SqlReadWriteProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SqlSecurityProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.StabilityProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.StorageHandlerProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.StreamingTableProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.StrictProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.Tags'>: <PropertiesLocation.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.properties.TemporaryProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.ToTableProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.TransientProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.TransformModelProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.ddl.MergeTreeTTL'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.UnloggedProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.UsingProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.UsingTemplateProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ViewAttributeProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.VirtualProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.VolatileProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.WithDataProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.WithJournalTableProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.WithProcedureOptions'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.WithSchemaBindingProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.WithSystemVersioningProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ForceProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>}
RESERVED_KEYWORDS =
{'rollup', 'collate', 'select', 'in', 'join', 'escape', 'else', 'as', 'of', 'not', 'grouping', 'contains', 'cast', 'cube', 'proto', 'or', 'ignore', 'no', 'respect', 'where', 'merge', 'set', 'unnest', 'at', 'left', 'all', 'lookup', 'union', 'within', 'extract', 'partition', 'between', 'when', 'struct', 'distinct', 'recursive', 'hash', 'desc', 'some', 'rows', 'null', 'false', 'from', 'fetch', 'treat', 'interval', 'define', 'unbounded', 'on', 'preceding', 'to', 'true', 'exists', 'groups', 'exclude', 'inner', 'natural', 'following', 'cross', 'new', 'create', 'window', 'assert_rows_modified', 'enum', 'with', 'asc', 'is', 'right', 'default', 'into', 'range', 'array', 'order', 'over', 'full', 'for', 'having', 'intersect', 'any', 'nulls', 'lateral', 'and', 'case', 'group', 'by', 'tablesample', 'using', 'current', 'limit', 'like', 'except', 'if', 'then', 'outer', 'qualify', 'end'}
567 def column_parts(self, expression: exp.Column) -> str: 568 if expression.meta.get("quoted_column"): 569 # If a column reference is of the form `dataset.table`.name, we need 570 # to preserve the quoted table path, otherwise the reference breaks 571 table_parts = ".".join(p.name for p in expression.parts[:-1]) 572 table_path = self.sql(exp.Identifier(this=table_parts, quoted=True)) 573 return f"{table_path}.{self.sql(expression, 'this')}" 574 575 return super().column_parts(expression)
577 def table_parts(self, expression: exp.Table) -> str: 578 # Depending on the context, `x.y` may not resolve to the same data source as `x`.`y`, so 579 # we need to make sure the correct quoting is used in each case. 580 # 581 # For example, if there is a CTE x that clashes with a schema name, then the former will 582 # return the table y in that schema, whereas the latter will return the CTE's y column: 583 # 584 # - WITH x AS (SELECT [1, 2] AS y) SELECT * FROM x, `x.y` -> cross join 585 # - WITH x AS (SELECT [1, 2] AS y) SELECT * FROM x, `x`.`y` -> implicit unnest 586 if expression.meta.get("quoted_table"): 587 table_parts = ".".join(p.name for p in expression.parts) 588 return self.sql(exp.Identifier(this=table_parts, quoted=True)) 589 590 return super().table_parts(expression)
592 def timetostr_sql(self, expression: exp.TimeToStr) -> str: 593 this = expression.this 594 if isinstance(this, exp.TsOrDsToDatetime): 595 func_name = "FORMAT_DATETIME" 596 elif isinstance(this, exp.TsOrDsToTimestamp): 597 func_name = "FORMAT_TIMESTAMP" 598 elif isinstance(this, exp.TsOrDsToTime): 599 func_name = "FORMAT_TIME" 600 else: 601 func_name = "FORMAT_DATE" 602 603 time_expr = this if isinstance(this, self.TS_OR_DS_TYPES) else expression 604 return self.func( 605 func_name, self.format_time(expression), time_expr.this, expression.args.get("zone") 606 )
616 def attimezone_sql(self, expression: exp.AtTimeZone) -> str: 617 parent = expression.parent 618 619 # BigQuery allows CAST(.. AS {STRING|TIMESTAMP} [FORMAT <fmt> [AT TIME ZONE <tz>]]). 620 # Only the TIMESTAMP one should use the below conversion, when AT TIME ZONE is included. 621 if not isinstance(parent, exp.Cast) or not parent.to.is_type("text"): 622 return self.func( 623 "TIMESTAMP", self.func("DATETIME", expression.this, expression.args.get("zone")) 624 ) 625 626 return super().attimezone_sql(expression)
631 def bracket_sql(self, expression: exp.Bracket) -> str: 632 this = expression.this 633 expressions = expression.expressions 634 635 if len(expressions) == 1 and this and this.is_type(exp.DType.STRUCT): 636 arg = expressions[0] 637 if arg.type is None: 638 from sqlglot.optimizer.annotate_types import annotate_types 639 640 arg = annotate_types(arg, dialect=self.dialect) 641 642 if arg.type and arg.type.this in exp.DataType.TEXT_TYPES: 643 # BQ doesn't support bracket syntax with string values for structs 644 return f"{self.sql(this)}.{arg.name}" 645 646 expressions_sql = self.expressions(expression, flat=True) 647 offset = expression.args.get("offset") 648 649 if offset == 0: 650 expressions_sql = f"OFFSET({expressions_sql})" 651 elif offset == 1: 652 expressions_sql = f"ORDINAL({expressions_sql})" 653 elif offset is not None: 654 self.unsupported(f"Unsupported array offset: {offset}") 655 656 if expression.args.get("safe"): 657 expressions_sql = f"SAFE_{expressions_sql}" 658 659 return f"{self.sql(this)}[{expressions_sql}]"
669 def contains_sql(self, expression: exp.Contains) -> str: 670 this = expression.this 671 expr = expression.expression 672 673 if isinstance(this, exp.Lower) and isinstance(expr, exp.Lower): 674 this = this.this 675 expr = expr.this 676 677 return self.func("CONTAINS_SUBSTR", this, expr, expression.args.get("json_scope"))
def
cast_sql( self, expression: sqlglot.expressions.functions.Cast, safe_prefix: str | None = None) -> str:
679 def cast_sql(self, expression: exp.Cast, safe_prefix: str | None = None) -> str: 680 this = expression.this 681 682 # This ensures that inline type-annotated ARRAY literals like ARRAY<INT64>[1, 2, 3] 683 # are roundtripped unaffected. The inner check excludes ARRAY(SELECT ...) expressions, 684 # because they aren't literals and so the above syntax is invalid BigQuery. 685 if isinstance(this, exp.Array): 686 elem = seq_get(this.expressions, 0) 687 if not (elem and elem.find(exp.Query)): 688 return f"{self.sql(expression, 'to')}{self.sql(this)}" 689 690 return super().cast_sql(expression, safe_prefix=safe_prefix)
Inherited Members
- sqlglot.generator.Generator
- Generator
- IGNORE_NULLS_BEFORE_ORDER
- LOCKING_READS_SUPPORTED
- WRAP_DERIVED_VALUES
- CREATE_FUNCTION_RETURN_AS
- MATCHED_BY_SOURCE
- SUPPORTS_MERGE_WHERE
- SINGLE_STRING_INTERVAL
- GROUPINGS_SEP
- INDEX_ON
- INOUT_SEPARATOR
- DIRECTED_JOINS
- QUERY_HINT_SEP
- IS_BOOL_ALLOWED
- DUPLICATE_KEY_UPDATE_WITH_SET
- LIMIT_IS_TOP
- RETURNING_END
- EXTRACT_ALLOWS_QUOTES
- TZ_TO_WITH_TIME_ZONE
- SELECT_KINDS
- VALUES_AS_TABLE
- ALTER_TABLE_INCLUDE_COLUMN_KEYWORD
- AGGREGATE_FILTER_SUPPORTED
- SEMI_ANTI_JOIN_WITH_SIDE
- COMPUTED_COLUMN_WITH_TYPE
- SUPPORTS_TABLE_COPY
- TABLESAMPLE_REQUIRES_PARENS
- TABLESAMPLE_SIZE_IS_ROWS
- TABLESAMPLE_KEYWORDS
- TABLESAMPLE_WITH_METHOD
- TABLESAMPLE_SEED_KEYWORD
- DATA_TYPE_SPECIFIERS_ALLOWED
- ENSURE_BOOLS
- CTE_RECURSIVE_KEYWORD_REQUIRED
- SUPPORTS_SINGLE_ARG_CONCAT
- LAST_DAY_SUPPORTS_DATE_PART
- INSERT_OVERWRITE
- SUPPORTS_SELECT_INTO
- SUPPORTS_UNLOGGED_TABLES
- SUPPORTS_CREATE_TABLE_LIKE
- LIKE_PROPERTY_INSIDE_SCHEMA
- MULTI_ARG_DISTINCT
- JSON_TYPE_REQUIRED_FOR_EXTRACTION
- JSON_PATH_BRACKETED_KEY_SUPPORTED
- SUPPORTS_WINDOW_EXCLUDE
- SET_OP_MODIFIERS
- COPY_PARAMS_ARE_WRAPPED
- COPY_PARAMS_EQ_REQUIRED
- COPY_HAS_INTO_KEYWORD
- UNICODE_SUBSTITUTE
- STAR_EXCEPT
- QUOTE_JSON_PATH
- PAD_FILL_PATTERN_IS_REQUIRED
- ARRAY_CONCAT_IS_VAR_LEN
- SUPPORTS_CONVERT_TIMEZONE
- SUPPORTS_MEDIAN
- ALTER_SET_WRAPPED
- NORMALIZE_EXTRACT_DATE_PARTS
- PARSE_JSON_NAME
- ARRAY_SIZE_NAME
- ALTER_SET_TYPE
- ARRAY_SIZE_DIM_REQUIRED
- SUPPORTS_BETWEEN_FLAGS
- SUPPORTS_LIKE_QUANTIFIERS
- MATCH_AGAINST_TABLE_PREFIX
- SET_ASSIGNMENT_REQUIRES_VARIABLE_KEYWORD
- UPDATE_STATEMENT_SUPPORTS_FROM
- STAR_EXCLUDE_REQUIRES_DERIVED_TABLE
- SUPPORTS_DROP_ALTER_ICEBERG_PROPERTY
- UNSUPPORTED_TYPES
- TIME_PART_SINGULARS
- TOKEN_MAPPING
- STRUCT_DELIMITER
- PARAMETER_TOKEN
- EXPRESSION_PRECEDES_PROPERTIES_CREATABLES
- WITH_SEPARATED_COMMENTS
- EXCLUDE_COMMENTS
- UNWRAPPED_INTERVAL_VALUES
- PARAMETERIZABLE_TEXT_TYPES
- EXPRESSIONS_WITHOUT_NESTED_CTES
- RESPECT_IGNORE_NULLS_UNSUPPORTED_EXPRESSIONS
- SENTINEL_LINE_BREAK
- pretty
- identify
- normalize
- pad
- unsupported_level
- max_unsupported
- leading_comma
- max_text_width
- comments
- dialect
- normalize_functions
- unsupported_messages
- generate
- preprocess
- unsupported
- sep
- seg
- sanitize_comment
- maybe_comment
- wrap
- no_identify
- normalize_func
- indent
- sql
- uncache_sql
- cache_sql
- characterset_sql
- column_sql
- pseudocolumn_sql
- columnposition_sql
- columndef_sql
- columnconstraint_sql
- computedcolumnconstraint_sql
- autoincrementcolumnconstraint_sql
- compresscolumnconstraint_sql
- generatedasidentitycolumnconstraint_sql
- generatedasrowcolumnconstraint_sql
- periodforsystemtimeconstraint_sql
- notnullcolumnconstraint_sql
- primarykeycolumnconstraint_sql
- uniquecolumnconstraint_sql
- inoutcolumnconstraint_sql
- createable_sql
- create_sql
- sequenceproperties_sql
- triggerproperties_sql
- triggerreferencing_sql
- triggerevent_sql
- clone_sql
- describe_sql
- heredoc_sql
- prepend_ctes
- with_sql
- cte_sql
- tablealias_sql
- bitstring_sql
- hexstring_sql
- bytestring_sql
- unicodestring_sql
- rawstring_sql
- datatypeparam_sql
- datatype_sql
- directory_sql
- delete_sql
- drop_sql
- set_operation
- set_operations
- fetch_sql
- limitoptions_sql
- filter_sql
- hint_sql
- indexparameters_sql
- index_sql
- identifier_sql
- hex_sql
- lowerhex_sql
- inputoutputformat_sql
- national_sql
- partition_sql
- properties_sql
- root_properties
- properties
- with_properties
- locate_properties
- property_name
- property_sql
- uuidproperty_sql
- likeproperty_sql
- fallbackproperty_sql
- journalproperty_sql
- freespaceproperty_sql
- checksumproperty_sql
- mergeblockratioproperty_sql
- moduleproperty_sql
- datablocksizeproperty_sql
- blockcompressionproperty_sql
- isolatedloadingproperty_sql
- partitionboundspec_sql
- partitionedofproperty_sql
- lockingproperty_sql
- withdataproperty_sql
- withsystemversioningproperty_sql
- insert_sql
- introducer_sql
- kill_sql
- pseudotype_sql
- objectidentifier_sql
- onconflict_sql
- returning_sql
- rowformatdelimitedproperty_sql
- withtablehint_sql
- indextablehint_sql
- historicaldata_sql
- table_sql
- tablefromrows_sql
- tablesample_sql
- pivot_sql
- tuple_sql
- update_sql
- values_sql
- var_sql
- into_sql
- from_sql
- groupingsets_sql
- rollup_sql
- rollupindex_sql
- rollupproperty_sql
- cube_sql
- group_sql
- having_sql
- connect_sql
- prior_sql
- join_sql
- lambda_sql
- lateral_op
- lateral_sql
- limit_sql
- offset_sql
- setitem_sql
- set_sql
- queryband_sql
- pragma_sql
- lock_sql
- literal_sql
- escape_str
- loaddata_sql
- null_sql
- boolean_sql
- booland_sql
- boolor_sql
- order_sql
- withfill_sql
- cluster_sql
- distribute_sql
- sort_sql
- ordered_sql
- matchrecognizemeasure_sql
- matchrecognize_sql
- query_modifiers
- options_modifier
- for_modifiers
- queryoption_sql
- offset_limit_modifiers
- after_limit_modifiers
- select_sql
- schema_sql
- schema_columns_sql
- star_sql
- parameter_sql
- sessionparameter_sql
- placeholder_sql
- subquery_sql
- qualify_sql
- unnest_sql
- prewhere_sql
- where_sql
- window_sql
- partition_by_sql
- windowspec_sql
- withingroup_sql
- between_sql
- bracket_offset_expressions
- all_sql
- any_sql
- exists_sql
- case_sql
- constraint_sql
- nextvaluefor_sql
- extract_sql
- trim_sql
- convert_concat_args
- concat_sql
- concatws_sql
- check_sql
- foreignkey_sql
- primarykey_sql
- if_sql
- matchagainst_sql
- jsonkeyvalue_sql
- jsonpath_sql
- json_path_part
- formatjson_sql
- formatphrase_sql
- jsonarray_sql
- jsonarrayagg_sql
- jsoncolumndef_sql
- jsonschema_sql
- jsontable_sql
- openjsoncolumndef_sql
- openjson_sql
- in_sql
- interval_sql
- return_sql
- reference_sql
- anonymous_sql
- paren_sql
- neg_sql
- not_sql
- alias_sql
- pivotalias_sql
- aliases_sql
- atindex_sql
- fromtimezone_sql
- add_sql
- and_sql
- or_sql
- xor_sql
- connector_sql
- bitwiseand_sql
- bitwiseleftshift_sql
- bitwisenot_sql
- bitwiseor_sql
- bitwiserightshift_sql
- bitwisexor_sql
- strtotime_sql
- currentdate_sql
- collate_sql
- command_sql
- comment_sql
- mergetreettlaction_sql
- mergetreettl_sql
- transaction_sql
- commit_sql
- rollback_sql
- altercolumn_sql
- alterindex_sql
- alterdiststyle_sql
- altersortkey_sql
- alterrename_sql
- renamecolumn_sql
- alterset_sql
- alter_sql
- altersession_sql
- add_column_sql
- droppartition_sql
- addconstraint_sql
- addpartition_sql
- distinct_sql
- ignorenulls_sql
- respectnulls_sql
- havingmax_sql
- intdiv_sql
- dpipe_sql
- div_sql
- safedivide_sql
- overlaps_sql
- distance_sql
- dot_sql
- propertyeq_sql
- escape_sql
- glob_sql
- gt_sql
- gte_sql
- is_sql
- like_sql
- ilike_sql
- match_sql
- similarto_sql
- lt_sql
- lte_sql
- mul_sql
- neq_sql
- nullsafeeq_sql
- nullsafeneq_sql
- sub_sql
- jsoncast_sql
- try_sql
- log_sql
- use_sql
- binary
- ceil_floor
- function_fallback_sql
- func
- format_args
- too_wide
- format_time
- expressions
- op_expressions
- naked_property
- tag_sql
- token_sql
- userdefinedfunction_sql
- joinhint_sql
- kwarg_sql
- when_sql
- whens_sql
- merge_sql
- tochar_sql
- tonumber_sql
- dictproperty_sql
- dictrange_sql
- dictsubproperty_sql
- duplicatekeyproperty_sql
- uniquekeyproperty_sql
- distributedbyproperty_sql
- oncluster_sql
- clusteredbyproperty_sql
- anyvalue_sql
- querytransform_sql
- indexconstraintoption_sql
- checkcolumnconstraint_sql
- indexcolumnconstraint_sql
- nvl2_sql
- comprehension_sql
- columnprefix_sql
- opclass_sql
- predict_sql
- generateembedding_sql
- generatetext_sql
- generatetable_sql
- generatebool_sql
- generateint_sql
- generatedouble_sql
- mltranslate_sql
- mlforecast_sql
- aiforecast_sql
- featuresattime_sql
- vectorsearch_sql
- forin_sql
- refresh_sql
- toarray_sql
- tsordstotime_sql
- tsordstotimestamp_sql
- tsordstodatetime_sql
- tsordstodate_sql
- unixdate_sql
- lastday_sql
- dateadd_sql
- arrayany_sql
- struct_sql
- partitionrange_sql
- truncatetable_sql
- convert_sql
- copyparameter_sql
- credentials_sql
- copy_sql
- semicolon_sql
- datadeletionproperty_sql
- maskingpolicycolumnconstraint_sql
- gapfill_sql
- scope_resolution
- scoperesolution_sql
- parsejson_sql
- rand_sql
- changes_sql
- pad_sql
- summarize_sql
- explodinggenerateseries_sql
- converttimezone_sql
- json_sql
- jsonvalue_sql
- skipjsoncolumn_sql
- conditionalinsert_sql
- multitableinserts_sql
- oncondition_sql
- jsonextractquote_sql
- jsonexists_sql
- arrayagg_sql
- slice_sql
- apply_sql
- grant_sql
- revoke_sql
- grantprivilege_sql
- grantprincipal_sql
- columns_sql
- overlay_sql
- todouble_sql
- string_sql
- median_sql
- overflowtruncatebehavior_sql
- unixseconds_sql
- arraysize_sql
- attach_sql
- detach_sql
- attachoption_sql
- watermarkcolumnconstraint_sql
- encodeproperty_sql
- includeproperty_sql
- xmlelement_sql
- xmlkeyvalueoption_sql
- partitionbyrangeproperty_sql
- partitionbyrangepropertydynamic_sql
- unpivotcolumns_sql
- analyzesample_sql
- analyzestatistics_sql
- analyzehistogram_sql
- analyzedelete_sql
- analyzelistchainedrows_sql
- analyzevalidate_sql
- analyze_sql
- xmltable_sql
- xmlnamespace_sql
- export_sql
- declare_sql
- declareitem_sql
- recursivewithsearch_sql
- parameterizedagg_sql
- anonymousaggfunc_sql
- combinedaggfunc_sql
- combinedparameterizedagg_sql
- show_sql
- install_sql
- get_put_sql
- translatecharacters_sql
- decodecase_sql
- semanticview_sql
- getextract_sql
- datefromunixdate_sql
- space_sql
- buildproperty_sql
- refreshtriggerproperty_sql
- modelattribute_sql
- directorystage_sql
- uuid_sql
- initcap_sql
- localtime_sql
- localtimestamp_sql
- weekstart_sql
- chr_sql
- block_sql
- storedprocedure_sql
- ifblock_sql
- whileblock_sql
- execute_sql
- executesql_sql
- altermodifysqlsecurity_sql
- usingproperty_sql
- renameindex_sql