sqlglot.generators.mysql
1from __future__ import annotations 2 3import typing as t 4 5from sqlglot import exp, generator, transforms 6from sqlglot.dialects.dialect import ( 7 arrow_json_extract_sql, 8 build_date_delta, 9 build_date_delta_with_interval, 10 date_add_interval_sql, 11 datestrtodate_sql, 12 length_or_char_length_sql, 13 max_or_greatest, 14 min_or_least, 15 no_ilike_sql, 16 no_paren_current_date_sql, 17 no_pivot_sql, 18 no_tablesample_sql, 19 no_trycast_sql, 20 if_sql, 21 remove_ts_or_ds_to_date, 22 rename_func, 23 strposition_sql, 24 unit_to_var, 25 trim_sql, 26 timestrtotime_sql, 27) 28from sqlglot.generator import unsupported_args 29from collections import defaultdict 30 31 32def _date_trunc_sql(self: MySQLGenerator, expression: exp.DateTrunc) -> str: 33 expr = self.sql(expression, "this") 34 unit_expr = expression.args.get("unit") 35 unit = ( 36 self.weekstart_name(unit_expr) 37 if isinstance(unit_expr, exp.WeekStart) 38 else expression.text("unit").upper() 39 ) 40 41 if unit == "WEEK": 42 concat = f"CONCAT(YEAR({expr}), ' ', WEEK({expr}, 1), ' 1')" 43 date_format = "%Y %u %w" 44 elif unit == "MONTH": 45 concat = f"CONCAT(YEAR({expr}), ' ', MONTH({expr}), ' 1')" 46 date_format = "%Y %c %e" 47 elif unit == "QUARTER": 48 concat = f"CONCAT(YEAR({expr}), ' ', QUARTER({expr}) * 3 - 2, ' 1')" 49 date_format = "%Y %c %e" 50 elif unit == "YEAR": 51 concat = f"CONCAT(YEAR({expr}), ' 1 1')" 52 date_format = "%Y %c %e" 53 else: 54 if unit != "DAY": 55 self.unsupported(f"Unexpected interval unit: {unit}") 56 return self.func("DATE", expr) 57 58 return self.func("STR_TO_DATE", concat, f"'{date_format}'") 59 60 61def _str_to_date_sql( 62 self: MySQLGenerator, expression: exp.StrToDate | exp.StrToTime | exp.TsOrDsToDate 63) -> str: 64 return self.func("STR_TO_DATE", expression.this, self.format_time(expression)) 65 66 67def _unix_to_time_sql(self: MySQLGenerator, expression: exp.UnixToTime) -> str: 68 scale = expression.args.get("scale") 69 timestamp = expression.this 70 71 if scale in (None, exp.UnixToTime.SECONDS): 72 return self.func("FROM_UNIXTIME", timestamp, self.format_time(expression)) 73 74 return self.func( 75 "FROM_UNIXTIME", 76 exp.Div(this=timestamp, expression=exp.func("POW", 10, scale)), 77 self.format_time(expression), 78 ) 79 80 81def date_add_sql( 82 kind: str, 83) -> t.Callable[[generator.Generator, exp.Expr], str]: 84 def func(self: generator.Generator, expression: exp.Expr) -> str: 85 return self.func( 86 f"DATE_{kind}", 87 expression.this, 88 exp.Interval(this=expression.expression, unit=unit_to_var(expression)), 89 ) 90 91 return func 92 93 94_MAKE_INTERVAL_UNIT_ALIASES = { 95 "years": "year", 96 "months": "month", 97 "weeks": "week", 98 "days": "day", 99 "hours": "hour", 100 "minutes": "minute", 101 "mins": "minute", 102 "seconds": "second", 103 "secs": "second", 104} 105 106 107def _ts_or_ds_to_date_sql(self: MySQLGenerator, expression: exp.TsOrDsToDate) -> str: 108 time_format = expression.args.get("format") 109 return _str_to_date_sql(self, expression) if time_format else self.func("DATE", expression.this) 110 111 112class MySQLGenerator(generator.Generator): 113 BYTE_STRING_FUNCTION = "UNHEX" 114 SELECT_KINDS: tuple[str, ...] = () 115 TRY_SUPPORTED = False 116 SUPPORTS_UESCAPE = False 117 SUPPORTS_DECODE_CASE = False 118 SUPPORTS_MODIFY_COLUMN = True 119 SUPPORTS_CHANGE_COLUMN = True 120 SUPPORTS_ALTER_COLUMN_NULLABILITY = True 121 122 AFTER_HAVING_MODIFIER_TRANSFORMS = generator.AFTER_HAVING_MODIFIER_TRANSFORMS 123 124 INTERVAL_ALLOWS_PLURAL_FORM = False 125 LOCKING_READS_SUPPORTED = True 126 CAST_TO_INT_ROUNDS = True 127 NULL_ORDERING_SUPPORTED: bool | None = None 128 JOIN_HINTS = False 129 TABLE_HINTS = True 130 DUPLICATE_KEY_UPDATE_WITH_SET = False 131 QUERY_HINT_SEP = " " 132 VALUES_AS_TABLE = False 133 NVL2_SUPPORTED = False 134 LAST_DAY_SUPPORTS_DATE_PART = False 135 JSON_TYPE_REQUIRED_FOR_EXTRACTION = True 136 JSON_PATH_BRACKETED_KEY_SUPPORTED = False 137 JSON_KEY_VALUE_PAIR_SEP = "," 138 SUPPORTS_TO_NUMBER = False 139 PARSE_JSON_NAME: str | None = None 140 PAD_FILL_PATTERN_IS_REQUIRED = True 141 WRAP_DERIVED_VALUES = False 142 VARCHAR_REQUIRES_SIZE = True 143 SUPPORTS_MEDIAN = False 144 UPDATE_STATEMENT_SUPPORTS_FROM = False 145 146 ALTER_PARTITION_OPTIONS: t.ClassVar[tuple[type[exp.Expr], ...]] = ( 147 exp.PartitionByListProperty, 148 exp.PartitionByRangeProperty, 149 ) 150 151 TRANSFORMS = { 152 **generator.Generator.TRANSFORMS, 153 exp.ArrayAgg: rename_func("GROUP_CONCAT"), 154 exp.BitwiseAndAgg: rename_func("BIT_AND"), 155 exp.BitwiseOrAgg: rename_func("BIT_OR"), 156 exp.BitwiseXorAgg: rename_func("BIT_XOR"), 157 exp.BitwiseCount: rename_func("BIT_COUNT"), 158 exp.Chr: lambda self, e: self.chr_sql(e, "CHAR"), 159 exp.CurrentDate: no_paren_current_date_sql, 160 exp.CurrentVersion: rename_func("VERSION"), 161 exp.DateDiff: remove_ts_or_ds_to_date( 162 lambda self, e: self.func("DATEDIFF", e.this, e.expression), ("this", "expression") 163 ), 164 exp.DateAdd: date_add_sql("ADD"), 165 exp.DateStrToDate: datestrtodate_sql, 166 exp.DateSub: date_add_sql("SUB"), 167 exp.DateTrunc: _date_trunc_sql, 168 exp.Day: remove_ts_or_ds_to_date(), 169 exp.DayOfMonth: remove_ts_or_ds_to_date(rename_func("DAYOFMONTH")), 170 exp.DayOfWeek: remove_ts_or_ds_to_date(rename_func("DAYOFWEEK")), 171 exp.DayOfYear: remove_ts_or_ds_to_date(rename_func("DAYOFYEAR")), 172 exp.GroupConcat: lambda self, e: ( 173 f"""GROUP_CONCAT({self.sql(e, "this")} SEPARATOR {self.sql(e, "separator") or "','"})""" 174 ), 175 exp.ILike: no_ilike_sql, 176 # https://dev.mysql.com/doc/refman/9.7/en/flow-control-functions.html#function_if 177 exp.If: if_sql(false_value="NULL"), 178 exp.JSONExtractScalar: arrow_json_extract_sql, 179 exp.Length: length_or_char_length_sql, 180 exp.LogicalOr: rename_func("MAX"), 181 exp.LogicalAnd: rename_func("MIN"), 182 exp.Max: max_or_greatest, 183 exp.Min: min_or_least, 184 exp.Month: remove_ts_or_ds_to_date(), 185 exp.NullSafeEQ: lambda self, e: self.binary(e, "<=>"), 186 exp.NullSafeNEQ: lambda self, e: f"NOT {self.binary(e, '<=>')}", 187 exp.NumberToStr: rename_func("FORMAT"), 188 exp.Pivot: no_pivot_sql, 189 exp.Select: transforms.preprocess( 190 [ 191 transforms.eliminate_distinct_on, 192 transforms.eliminate_semi_and_anti_joins, 193 transforms.eliminate_qualify, 194 transforms.eliminate_full_outer_join, 195 transforms.unnest_generate_date_array_using_recursive_cte, 196 ] 197 ), 198 exp.Stddev: rename_func("STDDEV_SAMP"), 199 exp.StrPosition: lambda self, e: strposition_sql( 200 self, e, func_name="LOCATE", supports_position=True 201 ), 202 exp.StrToDate: _str_to_date_sql, 203 exp.StrToTime: _str_to_date_sql, 204 exp.Stuff: rename_func("INSERT"), 205 exp.SessionUser: lambda *_: "SESSION_USER()", 206 exp.TableSample: no_tablesample_sql, 207 exp.TimeFromParts: rename_func("MAKETIME"), 208 exp.TimestampAdd: date_add_interval_sql("DATE", "ADD"), 209 exp.TimestampDiff: lambda self, e: self.func( 210 "TIMESTAMPDIFF", unit_to_var(e), e.expression, e.this 211 ), 212 exp.TimestampSub: date_add_interval_sql("DATE", "SUB"), 213 exp.TimeStrToUnix: rename_func("UNIX_TIMESTAMP"), 214 exp.TimeStrToTime: lambda self, e: timestrtotime_sql( 215 self, 216 e, 217 include_precision=not e.args.get("zone"), 218 ), 219 exp.TimeToStr: remove_ts_or_ds_to_date( 220 lambda self, e: self.func("DATE_FORMAT", e.this, self.format_time(e)) 221 ), 222 exp.Trim: trim_sql, 223 exp.Trunc: lambda self, e: self.func( 224 "TRUNCATE", e.this, e.args.get("decimals") or exp.Literal.number(0) 225 ), 226 exp.TryCast: no_trycast_sql, 227 exp.TsOrDsAdd: date_add_sql("ADD"), 228 exp.TsOrDsDiff: lambda self, e: self.func("DATEDIFF", e.this, e.expression), 229 exp.TsOrDsToDate: _ts_or_ds_to_date_sql, 230 exp.Unicode: lambda self, e: f"ORD(CONVERT({self.sql(e.this)} USING utf32))", 231 exp.UnixToTime: _unix_to_time_sql, 232 exp.Variance: rename_func("VAR_SAMP"), 233 exp.VariancePop: rename_func("VAR_POP"), 234 exp.Week: remove_ts_or_ds_to_date(), 235 exp.WeekOfYear: remove_ts_or_ds_to_date(rename_func("WEEKOFYEAR")), 236 exp.Year: remove_ts_or_ds_to_date(), 237 exp.UtcTimestamp: rename_func("UTC_TIMESTAMP"), 238 exp.UtcTime: rename_func("UTC_TIME"), 239 } 240 241 UNSIGNED_TYPE_MAPPING: t.ClassVar = { 242 exp.DType.UBIGINT: "BIGINT", 243 exp.DType.UINT: "INT", 244 exp.DType.UMEDIUMINT: "MEDIUMINT", 245 exp.DType.USMALLINT: "SMALLINT", 246 exp.DType.UTINYINT: "TINYINT", 247 exp.DType.UDECIMAL: "DECIMAL", 248 exp.DType.UDOUBLE: "DOUBLE", 249 } 250 251 TIMESTAMP_TYPE_MAPPING: t.ClassVar = { 252 exp.DType.DATETIME2: "DATETIME", 253 exp.DType.SMALLDATETIME: "DATETIME", 254 exp.DType.TIMESTAMP: "DATETIME", 255 exp.DType.TIMESTAMPNTZ: "DATETIME", 256 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 257 exp.DType.TIMESTAMPLTZ: "TIMESTAMP", 258 } 259 260 TYPE_MAPPING: t.ClassVar = { 261 exp.DType.NCHAR: "CHAR", 262 exp.DType.NVARCHAR: "VARCHAR", 263 exp.DType.INET: "INET", 264 exp.DType.ROWVERSION: "VARBINARY", 265 exp.DType.UBIGINT: "BIGINT", 266 exp.DType.UINT: "INT", 267 exp.DType.UMEDIUMINT: "MEDIUMINT", 268 exp.DType.USMALLINT: "SMALLINT", 269 exp.DType.UTINYINT: "TINYINT", 270 exp.DType.UDECIMAL: "DECIMAL", 271 exp.DType.UDOUBLE: "DOUBLE", 272 exp.DType.DATETIME2: "DATETIME", 273 exp.DType.SMALLDATETIME: "DATETIME", 274 exp.DType.TIMESTAMP: "DATETIME", 275 exp.DType.TIMESTAMPNTZ: "DATETIME", 276 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 277 exp.DType.TIMESTAMPLTZ: "TIMESTAMP", 278 } 279 280 PROPERTIES_LOCATION: t.ClassVar = { 281 **generator.Generator.PROPERTIES_LOCATION, 282 exp.TransientProperty: exp.Properties.Location.UNSUPPORTED, 283 exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED, 284 exp.PartitionedByProperty: exp.Properties.Location.UNSUPPORTED, 285 exp.PartitionByRangeProperty: exp.Properties.Location.POST_SCHEMA, 286 exp.PartitionByListProperty: exp.Properties.Location.POST_SCHEMA, 287 exp.Property: exp.Properties.Location.POST_SCHEMA, 288 } 289 290 LIMIT_FETCH = "LIMIT" 291 292 LIMIT_ONLY_LITERALS = True 293 294 CHAR_CAST_MAPPING: t.ClassVar = dict.fromkeys( 295 ( 296 exp.DType.LONGTEXT, 297 exp.DType.LONGBLOB, 298 exp.DType.MEDIUMBLOB, 299 exp.DType.MEDIUMTEXT, 300 exp.DType.TEXT, 301 exp.DType.TINYBLOB, 302 exp.DType.TINYTEXT, 303 exp.DType.VARCHAR, 304 ), 305 "CHAR", 306 ) 307 SIGNED_CAST_MAPPING: t.ClassVar = dict.fromkeys( 308 ( 309 exp.DType.BIGINT, 310 exp.DType.BOOLEAN, 311 exp.DType.INT, 312 exp.DType.SMALLINT, 313 exp.DType.TINYINT, 314 exp.DType.MEDIUMINT, 315 ), 316 "SIGNED", 317 ) 318 319 # MySQL doesn't support many datatypes in cast. 320 # https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html#function_cast 321 CAST_MAPPING: t.ClassVar = { 322 exp.DType.LONGTEXT: "CHAR", 323 exp.DType.LONGBLOB: "CHAR", 324 exp.DType.MEDIUMBLOB: "CHAR", 325 exp.DType.MEDIUMTEXT: "CHAR", 326 exp.DType.TEXT: "CHAR", 327 exp.DType.TINYBLOB: "CHAR", 328 exp.DType.TINYTEXT: "CHAR", 329 exp.DType.VARCHAR: "CHAR", 330 exp.DType.BIGINT: "SIGNED", 331 exp.DType.BOOLEAN: "SIGNED", 332 exp.DType.INT: "SIGNED", 333 exp.DType.SMALLINT: "SIGNED", 334 exp.DType.TINYINT: "SIGNED", 335 exp.DType.MEDIUMINT: "SIGNED", 336 exp.DType.UBIGINT: "UNSIGNED", 337 } 338 339 TIMESTAMP_FUNC_TYPES: t.ClassVar = { 340 exp.DType.TIMESTAMPTZ, 341 exp.DType.TIMESTAMPLTZ, 342 } 343 344 # https://dev.mysql.com/doc/refman/8.0/en/keywords.html 345 RESERVED_KEYWORDS = { 346 "accessible", 347 "add", 348 "all", 349 "alter", 350 "analyze", 351 "and", 352 "as", 353 "asc", 354 "asensitive", 355 "before", 356 "between", 357 "bigint", 358 "binary", 359 "blob", 360 "both", 361 "by", 362 "call", 363 "cascade", 364 "case", 365 "change", 366 "char", 367 "character", 368 "check", 369 "collate", 370 "column", 371 "condition", 372 "constraint", 373 "continue", 374 "convert", 375 "create", 376 "cross", 377 "cube", 378 "cume_dist", 379 "current_date", 380 "current_time", 381 "current_timestamp", 382 "current_user", 383 "cursor", 384 "database", 385 "databases", 386 "day_hour", 387 "day_microsecond", 388 "day_minute", 389 "day_second", 390 "dec", 391 "decimal", 392 "declare", 393 "default", 394 "delayed", 395 "delete", 396 "dense_rank", 397 "desc", 398 "describe", 399 "deterministic", 400 "distinct", 401 "distinctrow", 402 "div", 403 "double", 404 "drop", 405 "dual", 406 "each", 407 "else", 408 "elseif", 409 "empty", 410 "enclosed", 411 "escaped", 412 "except", 413 "exists", 414 "exit", 415 "explain", 416 "false", 417 "fetch", 418 "first_value", 419 "float", 420 "float4", 421 "float8", 422 "for", 423 "force", 424 "foreign", 425 "from", 426 "fulltext", 427 "function", 428 "generated", 429 "get", 430 "grant", 431 "group", 432 "grouping", 433 "groups", 434 "having", 435 "high_priority", 436 "hour_microsecond", 437 "hour_minute", 438 "hour_second", 439 "if", 440 "ignore", 441 "in", 442 "index", 443 "infile", 444 "inner", 445 "inout", 446 "insensitive", 447 "insert", 448 "int", 449 "int1", 450 "int2", 451 "int3", 452 "int4", 453 "int8", 454 "integer", 455 "intersect", 456 "interval", 457 "into", 458 "io_after_gtids", 459 "io_before_gtids", 460 "is", 461 "iterate", 462 "join", 463 "json_table", 464 "key", 465 "keys", 466 "kill", 467 "lag", 468 "last_value", 469 "lateral", 470 "lead", 471 "leading", 472 "leave", 473 "left", 474 "like", 475 "limit", 476 "linear", 477 "lines", 478 "load", 479 "localtime", 480 "localtimestamp", 481 "lock", 482 "long", 483 "longblob", 484 "longtext", 485 "loop", 486 "low_priority", 487 "master_bind", 488 "master_ssl_verify_server_cert", 489 "match", 490 "maxvalue", 491 "mediumblob", 492 "mediumint", 493 "mediumtext", 494 "middleint", 495 "minute_microsecond", 496 "minute_second", 497 "mod", 498 "modifies", 499 "natural", 500 "not", 501 "no_write_to_binlog", 502 "nth_value", 503 "ntile", 504 "null", 505 "numeric", 506 "of", 507 "on", 508 "optimize", 509 "optimizer_costs", 510 "option", 511 "optionally", 512 "or", 513 "order", 514 "out", 515 "outer", 516 "outfile", 517 "over", 518 "partition", 519 "percent_rank", 520 "precision", 521 "primary", 522 "procedure", 523 "purge", 524 "range", 525 "rank", 526 "read", 527 "reads", 528 "read_write", 529 "real", 530 "recursive", 531 "references", 532 "regexp", 533 "release", 534 "rename", 535 "repeat", 536 "replace", 537 "require", 538 "resignal", 539 "restrict", 540 "return", 541 "revoke", 542 "right", 543 "rlike", 544 "row", 545 "rows", 546 "row_number", 547 "schema", 548 "schemas", 549 "second_microsecond", 550 "select", 551 "sensitive", 552 "separator", 553 "set", 554 "show", 555 "signal", 556 "smallint", 557 "spatial", 558 "specific", 559 "sql", 560 "sqlexception", 561 "sqlstate", 562 "sqlwarning", 563 "sql_big_result", 564 "sql_calc_found_rows", 565 "sql_small_result", 566 "ssl", 567 "starting", 568 "stored", 569 "straight_join", 570 "system", 571 "table", 572 "terminated", 573 "then", 574 "tinyblob", 575 "tinyint", 576 "tinytext", 577 "to", 578 "trailing", 579 "trigger", 580 "true", 581 "undo", 582 "union", 583 "unique", 584 "unlock", 585 "unsigned", 586 "update", 587 "usage", 588 "use", 589 "using", 590 "utc_date", 591 "utc_time", 592 "utc_timestamp", 593 "values", 594 "varbinary", 595 "varchar", 596 "varcharacter", 597 "varying", 598 "virtual", 599 "when", 600 "where", 601 "while", 602 "window", 603 "with", 604 "write", 605 "xor", 606 "year_month", 607 "zerofill", 608 } 609 610 SQL_SECURITY_VIEW_LOCATION: t.ClassVar = exp.Properties.Location.POST_CREATE 611 612 def makeinterval_sql(self: MySQLGenerator, expression: exp.MakeInterval) -> str: 613 intervals: list[exp.Interval] = [] 614 for arg_key, value in expression.args.items(): 615 if value is None: 616 continue 617 618 if isinstance(value, exp.Kwarg): 619 unit_name = _MAKE_INTERVAL_UNIT_ALIASES.get( 620 value.this.name.lower(), value.this.name.lower() 621 ) 622 value = value.expression 623 else: 624 unit_name = arg_key 625 626 intervals.append(exp.Interval(this=value.copy(), unit=exp.var(unit_name.upper()))) 627 628 if not intervals: 629 return self.function_fallback_sql(expression) 630 631 parent = expression.parent 632 sep = " - " if isinstance(parent, exp.Sub) and parent.expression is expression else " + " 633 634 return sep.join(self.sql(interval) for interval in intervals) 635 636 def locate_properties(self, properties: exp.Properties) -> defaultdict: 637 locations = super().locate_properties(properties) 638 639 # MySQL puts SQL SECURITY before VIEW but after the schema for functions/procedures 640 if isinstance(create := properties.parent, exp.Create) and create.kind == "VIEW": 641 post_schema = locations[exp.Properties.Location.POST_SCHEMA] 642 for i, p in enumerate(post_schema): 643 if isinstance(p, exp.SqlSecurityProperty): 644 post_schema.pop(i) 645 locations[self.SQL_SECURITY_VIEW_LOCATION].append(p) 646 break 647 648 return locations 649 650 def computedcolumnconstraint_sql(self, expression: exp.ComputedColumnConstraint) -> str: 651 persisted = "STORED" if expression.args.get("persisted") else "VIRTUAL" 652 return f"GENERATED ALWAYS AS ({self.sql(expression.this.unnest())}) {persisted}" 653 654 def array_sql(self, expression: exp.Array) -> str: 655 self.unsupported("Arrays are not supported by MySQL") 656 return self.function_fallback_sql(expression) 657 658 def arraycontainsall_sql(self, expression: exp.ArrayContainsAll) -> str: 659 self.unsupported("Array operations are not supported by MySQL") 660 return self.function_fallback_sql(expression) 661 662 def arraycontainedby_sql(self, expression: exp.ArrayContainedBy) -> str: 663 self.unsupported("Array operations are not supported by MySQL") 664 return self.function_fallback_sql(expression) 665 666 def dpipe_sql(self, expression: exp.DPipe) -> str: 667 return self.func("CONCAT", *expression.flatten()) 668 669 def intdiv_sql(self, expression: exp.IntDiv) -> str: 670 this = self.sql(exp._wrap(expression.this, exp.Binary)) 671 divisor = self.sql(exp._wrap(expression.expression, exp.Binary)) 672 sql = f"{this} {self.maybe_comment('DIV', comments=expression.comments)} {divisor}" 673 674 parent = expression.parent 675 if isinstance(parent, (exp.Neg, exp.BitwiseNot)) or ( 676 isinstance(parent, (exp.Mul, exp.Div, exp.IntDiv, exp.Mod)) 677 and parent.expression is expression 678 ): 679 return f"({sql})" 680 681 return sql 682 683 def extract_sql(self, expression: exp.Extract) -> str: 684 unit = expression.name 685 if unit and unit.lower() == "epoch": 686 return self.func("UNIX_TIMESTAMP", expression.expression) 687 688 return super().extract_sql(expression) 689 690 def datatype_sql(self, expression: exp.DataType) -> str: 691 if ( 692 self.VARCHAR_REQUIRES_SIZE 693 and expression.is_type(exp.DType.VARCHAR) 694 and not expression.expressions 695 ): 696 # `VARCHAR` must always have a size - if it doesn't, we always generate `TEXT` 697 return "TEXT" 698 699 # https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html 700 result = super().datatype_sql(expression) 701 if expression.this in self.UNSIGNED_TYPE_MAPPING: 702 result = f"{result} UNSIGNED" 703 704 return result 705 706 def jsonarraycontains_sql(self, expression: exp.JSONArrayContains) -> str: 707 return f"{self.sql(expression, 'this')} MEMBER OF({self.sql(expression, 'expression')})" 708 709 def cast_sql(self, expression: exp.Cast, safe_prefix: str | None = None) -> str: 710 if expression.to.this in self.TIMESTAMP_FUNC_TYPES: 711 return self.func("TIMESTAMP", expression.this) 712 713 to = self.CAST_MAPPING.get(expression.to.this) 714 715 if to: 716 expression.to.set("this", to) 717 return super().cast_sql(expression) 718 719 def show_sql(self, expression: exp.Show) -> str: 720 this = f" {expression.name}" 721 full = " FULL" if expression.args.get("full") else "" 722 global_ = " GLOBAL" if expression.args.get("global_") else "" 723 724 target = self.sql(expression, "target") 725 726 # SHOW CREATE ... takes a possibly qualified name, it has no FROM clause 727 # https://dev.mysql.com/doc/refman/8.4/en/show-create-table.html 728 if expression.name.startswith("CREATE") and (db_id := self.sql(expression, "db")): 729 target = f"{db_id}.{target}" 730 db = "" 731 else: 732 db = self._prefixed_sql("FROM", expression, "db") 733 734 target = f" {target}" if target else "" 735 if expression.name in ("COLUMNS", "INDEX"): 736 target = f" FROM{target}" 737 elif expression.name == "GRANTS": 738 target = f" FOR{target}" 739 elif expression.name in ("LINKS", "PARTITIONS"): 740 target = f" ON{target}" if target else "" 741 elif expression.name == "PROJECTIONS": 742 target = f" ON TABLE{target}" if target else "" 743 744 like = self._prefixed_sql("LIKE", expression, "like") 745 where = self.sql(expression, "where") 746 747 types = self.expressions(expression, key="types") 748 types = f" {types}" if types else types 749 query = self._prefixed_sql("FOR QUERY", expression, "query") 750 751 if expression.name == "PROFILE": 752 offset = self._prefixed_sql("OFFSET", expression, "offset") 753 limit = self._prefixed_sql("LIMIT", expression, "limit") 754 else: 755 offset = "" 756 limit = self._oldstyle_limit_sql(expression) 757 758 log = self._prefixed_sql("IN", expression, "log") 759 position = self._prefixed_sql("FROM", expression, "position") 760 761 channel = self._prefixed_sql("FOR CHANNEL", expression, "channel") 762 763 if expression.name == "ENGINE": 764 mutex_or_status = " MUTEX" if expression.args.get("mutex") else " STATUS" 765 else: 766 mutex_or_status = "" 767 768 for_table = self._prefixed_sql("FOR TABLE", expression, "for_table") 769 for_group = self._prefixed_sql("FOR GROUP", expression, "for_group") 770 for_user = self._prefixed_sql("FOR USER", expression, "for_user") 771 for_role = self._prefixed_sql("FOR ROLE", expression, "for_role") 772 into_outfile = self._prefixed_sql("INTO OUTFILE", expression, "into_outfile") 773 json = " JSON" if expression.args.get("json") else "" 774 775 return f"SHOW{full}{global_}{this}{json}{target}{for_table}{types}{db}{query}{log}{position}{channel}{mutex_or_status}{like}{where}{offset}{limit}{for_group}{for_user}{for_role}{into_outfile}" 776 777 def alterrename_sql(self, expression: exp.AlterRename, include_to: bool = True) -> str: 778 """To avoid TO keyword in ALTER ... RENAME statements. 779 It's moved from Doris, because it's the same for all MySQL, Doris, and StarRocks. 780 """ 781 return super().alterrename_sql(expression, include_to=False) 782 783 def altercolumn_sql(self, expression: exp.AlterColumn) -> str: 784 dtype = self.sql(expression, "dtype") 785 if not dtype: 786 return super().altercolumn_sql(expression) 787 788 if expression.args.get("exists"): 789 self.unsupported("ALTER COLUMN IF EXISTS is not supported by this dialect") 790 791 this = self.sql(expression, "this") 792 null_constraint = self._alter_column_null_constraint_sql(expression) 793 return f"MODIFY COLUMN {this} {dtype}{null_constraint}" 794 795 def _prefixed_sql(self, prefix: str, expression: exp.Expr, arg: str) -> str: 796 sql = self.sql(expression, arg) 797 return f" {prefix} {sql}" if sql else "" 798 799 def _oldstyle_limit_sql(self, expression: exp.Show) -> str: 800 limit = self.sql(expression, "limit") 801 offset = self.sql(expression, "offset") 802 if limit: 803 limit_offset = f"{offset}, {limit}" if offset else limit 804 return f" LIMIT {limit_offset}" 805 return "" 806 807 def timestamptrunc_sql(self, expression: exp.TimestampTrunc) -> str: 808 unit = expression.args.get("unit") 809 if isinstance(unit, exp.WeekStart): 810 unit = exp.var(self.weekstart_name(unit)) 811 812 # Pick an old-enough date to avoid negative timestamp diffs 813 start_ts = "'0000-01-01 00:00:00'" 814 815 # Source: https://stackoverflow.com/a/32955740 816 timestamp_diff = build_date_delta(exp.TimestampDiff)([unit, start_ts, expression.this]) 817 interval = exp.Interval(this=timestamp_diff, unit=unit) 818 dateadd = build_date_delta_with_interval(exp.DateAdd)([start_ts, interval]) 819 820 return self.sql(dateadd) 821 822 def converttimezone_sql(self, expression: exp.ConvertTimezone) -> str: 823 from_tz = expression.args.get("source_tz") 824 to_tz = expression.args.get("target_tz") 825 dt = expression.args.get("timestamp") 826 827 return self.func("CONVERT_TZ", dt, from_tz, to_tz) 828 829 def attimezone_sql(self, expression: exp.AtTimeZone) -> str: 830 self.unsupported("AT TIME ZONE is not supported by MySQL") 831 return self.sql(expression.this) 832 833 def isascii_sql(self, expression: exp.IsAscii) -> str: 834 return f"REGEXP_LIKE({self.sql(expression.this)}, '^[[:ascii:]]*$')" 835 836 def ignorenulls_sql(self, expression: exp.IgnoreNulls) -> str: 837 # https://dev.mysql.com/doc/refman/8.4/en/window-function-descriptions.html 838 self.unsupported("MySQL does not support IGNORE NULLS.") 839 return self.sql(expression.this) 840 841 @unsupported_args("this") 842 def currentschema_sql(self, expression: exp.CurrentSchema) -> str: 843 return self.func("SCHEMA") 844 845 def partition_sql(self, expression: exp.Partition) -> str: 846 parent = expression.parent 847 if isinstance(parent, (exp.PartitionByRangeProperty, exp.PartitionByListProperty)): 848 return self.expressions(expression, flat=True) 849 return super().partition_sql(expression) 850 851 def _partition_by_sql( 852 self, expression: exp.PartitionByRangeProperty | exp.PartitionByListProperty, kind: str 853 ) -> str: 854 partitions = self.expressions(expression, key="partition_expressions", flat=True) 855 create = self.expressions(expression, key="create_expressions", flat=True) 856 return f"PARTITION BY {kind} ({partitions}) ({create})" 857 858 def partitionbyrangeproperty_sql(self, expression: exp.PartitionByRangeProperty) -> str: 859 return self._partition_by_sql(expression, "RANGE") 860 861 def partitionbylistproperty_sql(self, expression: exp.PartitionByListProperty) -> str: 862 return self._partition_by_sql(expression, "LIST") 863 864 def partitionlist_sql(self, expression: exp.PartitionList) -> str: 865 name = self.sql(expression, "this") 866 values = self.expressions(expression, flat=True) 867 return f"PARTITION {name} VALUES IN ({values})" 868 869 def partitionrange_sql(self, expression: exp.PartitionRange) -> str: 870 name = self.sql(expression, "this") 871 values = self.expressions(expression, flat=True) 872 return f"PARTITION {name} VALUES LESS THAN ({values})"
def
date_add_sql( kind: str) -> Callable[[sqlglot.generator.Generator, sqlglot.expressions.core.Expr], str]:
82def date_add_sql( 83 kind: str, 84) -> t.Callable[[generator.Generator, exp.Expr], str]: 85 def func(self: generator.Generator, expression: exp.Expr) -> str: 86 return self.func( 87 f"DATE_{kind}", 88 expression.this, 89 exp.Interval(this=expression.expression, unit=unit_to_var(expression)), 90 ) 91 92 return func
113class MySQLGenerator(generator.Generator): 114 BYTE_STRING_FUNCTION = "UNHEX" 115 SELECT_KINDS: tuple[str, ...] = () 116 TRY_SUPPORTED = False 117 SUPPORTS_UESCAPE = False 118 SUPPORTS_DECODE_CASE = False 119 SUPPORTS_MODIFY_COLUMN = True 120 SUPPORTS_CHANGE_COLUMN = True 121 SUPPORTS_ALTER_COLUMN_NULLABILITY = True 122 123 AFTER_HAVING_MODIFIER_TRANSFORMS = generator.AFTER_HAVING_MODIFIER_TRANSFORMS 124 125 INTERVAL_ALLOWS_PLURAL_FORM = False 126 LOCKING_READS_SUPPORTED = True 127 CAST_TO_INT_ROUNDS = True 128 NULL_ORDERING_SUPPORTED: bool | None = None 129 JOIN_HINTS = False 130 TABLE_HINTS = True 131 DUPLICATE_KEY_UPDATE_WITH_SET = False 132 QUERY_HINT_SEP = " " 133 VALUES_AS_TABLE = False 134 NVL2_SUPPORTED = False 135 LAST_DAY_SUPPORTS_DATE_PART = False 136 JSON_TYPE_REQUIRED_FOR_EXTRACTION = True 137 JSON_PATH_BRACKETED_KEY_SUPPORTED = False 138 JSON_KEY_VALUE_PAIR_SEP = "," 139 SUPPORTS_TO_NUMBER = False 140 PARSE_JSON_NAME: str | None = None 141 PAD_FILL_PATTERN_IS_REQUIRED = True 142 WRAP_DERIVED_VALUES = False 143 VARCHAR_REQUIRES_SIZE = True 144 SUPPORTS_MEDIAN = False 145 UPDATE_STATEMENT_SUPPORTS_FROM = False 146 147 ALTER_PARTITION_OPTIONS: t.ClassVar[tuple[type[exp.Expr], ...]] = ( 148 exp.PartitionByListProperty, 149 exp.PartitionByRangeProperty, 150 ) 151 152 TRANSFORMS = { 153 **generator.Generator.TRANSFORMS, 154 exp.ArrayAgg: rename_func("GROUP_CONCAT"), 155 exp.BitwiseAndAgg: rename_func("BIT_AND"), 156 exp.BitwiseOrAgg: rename_func("BIT_OR"), 157 exp.BitwiseXorAgg: rename_func("BIT_XOR"), 158 exp.BitwiseCount: rename_func("BIT_COUNT"), 159 exp.Chr: lambda self, e: self.chr_sql(e, "CHAR"), 160 exp.CurrentDate: no_paren_current_date_sql, 161 exp.CurrentVersion: rename_func("VERSION"), 162 exp.DateDiff: remove_ts_or_ds_to_date( 163 lambda self, e: self.func("DATEDIFF", e.this, e.expression), ("this", "expression") 164 ), 165 exp.DateAdd: date_add_sql("ADD"), 166 exp.DateStrToDate: datestrtodate_sql, 167 exp.DateSub: date_add_sql("SUB"), 168 exp.DateTrunc: _date_trunc_sql, 169 exp.Day: remove_ts_or_ds_to_date(), 170 exp.DayOfMonth: remove_ts_or_ds_to_date(rename_func("DAYOFMONTH")), 171 exp.DayOfWeek: remove_ts_or_ds_to_date(rename_func("DAYOFWEEK")), 172 exp.DayOfYear: remove_ts_or_ds_to_date(rename_func("DAYOFYEAR")), 173 exp.GroupConcat: lambda self, e: ( 174 f"""GROUP_CONCAT({self.sql(e, "this")} SEPARATOR {self.sql(e, "separator") or "','"})""" 175 ), 176 exp.ILike: no_ilike_sql, 177 # https://dev.mysql.com/doc/refman/9.7/en/flow-control-functions.html#function_if 178 exp.If: if_sql(false_value="NULL"), 179 exp.JSONExtractScalar: arrow_json_extract_sql, 180 exp.Length: length_or_char_length_sql, 181 exp.LogicalOr: rename_func("MAX"), 182 exp.LogicalAnd: rename_func("MIN"), 183 exp.Max: max_or_greatest, 184 exp.Min: min_or_least, 185 exp.Month: remove_ts_or_ds_to_date(), 186 exp.NullSafeEQ: lambda self, e: self.binary(e, "<=>"), 187 exp.NullSafeNEQ: lambda self, e: f"NOT {self.binary(e, '<=>')}", 188 exp.NumberToStr: rename_func("FORMAT"), 189 exp.Pivot: no_pivot_sql, 190 exp.Select: transforms.preprocess( 191 [ 192 transforms.eliminate_distinct_on, 193 transforms.eliminate_semi_and_anti_joins, 194 transforms.eliminate_qualify, 195 transforms.eliminate_full_outer_join, 196 transforms.unnest_generate_date_array_using_recursive_cte, 197 ] 198 ), 199 exp.Stddev: rename_func("STDDEV_SAMP"), 200 exp.StrPosition: lambda self, e: strposition_sql( 201 self, e, func_name="LOCATE", supports_position=True 202 ), 203 exp.StrToDate: _str_to_date_sql, 204 exp.StrToTime: _str_to_date_sql, 205 exp.Stuff: rename_func("INSERT"), 206 exp.SessionUser: lambda *_: "SESSION_USER()", 207 exp.TableSample: no_tablesample_sql, 208 exp.TimeFromParts: rename_func("MAKETIME"), 209 exp.TimestampAdd: date_add_interval_sql("DATE", "ADD"), 210 exp.TimestampDiff: lambda self, e: self.func( 211 "TIMESTAMPDIFF", unit_to_var(e), e.expression, e.this 212 ), 213 exp.TimestampSub: date_add_interval_sql("DATE", "SUB"), 214 exp.TimeStrToUnix: rename_func("UNIX_TIMESTAMP"), 215 exp.TimeStrToTime: lambda self, e: timestrtotime_sql( 216 self, 217 e, 218 include_precision=not e.args.get("zone"), 219 ), 220 exp.TimeToStr: remove_ts_or_ds_to_date( 221 lambda self, e: self.func("DATE_FORMAT", e.this, self.format_time(e)) 222 ), 223 exp.Trim: trim_sql, 224 exp.Trunc: lambda self, e: self.func( 225 "TRUNCATE", e.this, e.args.get("decimals") or exp.Literal.number(0) 226 ), 227 exp.TryCast: no_trycast_sql, 228 exp.TsOrDsAdd: date_add_sql("ADD"), 229 exp.TsOrDsDiff: lambda self, e: self.func("DATEDIFF", e.this, e.expression), 230 exp.TsOrDsToDate: _ts_or_ds_to_date_sql, 231 exp.Unicode: lambda self, e: f"ORD(CONVERT({self.sql(e.this)} USING utf32))", 232 exp.UnixToTime: _unix_to_time_sql, 233 exp.Variance: rename_func("VAR_SAMP"), 234 exp.VariancePop: rename_func("VAR_POP"), 235 exp.Week: remove_ts_or_ds_to_date(), 236 exp.WeekOfYear: remove_ts_or_ds_to_date(rename_func("WEEKOFYEAR")), 237 exp.Year: remove_ts_or_ds_to_date(), 238 exp.UtcTimestamp: rename_func("UTC_TIMESTAMP"), 239 exp.UtcTime: rename_func("UTC_TIME"), 240 } 241 242 UNSIGNED_TYPE_MAPPING: t.ClassVar = { 243 exp.DType.UBIGINT: "BIGINT", 244 exp.DType.UINT: "INT", 245 exp.DType.UMEDIUMINT: "MEDIUMINT", 246 exp.DType.USMALLINT: "SMALLINT", 247 exp.DType.UTINYINT: "TINYINT", 248 exp.DType.UDECIMAL: "DECIMAL", 249 exp.DType.UDOUBLE: "DOUBLE", 250 } 251 252 TIMESTAMP_TYPE_MAPPING: t.ClassVar = { 253 exp.DType.DATETIME2: "DATETIME", 254 exp.DType.SMALLDATETIME: "DATETIME", 255 exp.DType.TIMESTAMP: "DATETIME", 256 exp.DType.TIMESTAMPNTZ: "DATETIME", 257 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 258 exp.DType.TIMESTAMPLTZ: "TIMESTAMP", 259 } 260 261 TYPE_MAPPING: t.ClassVar = { 262 exp.DType.NCHAR: "CHAR", 263 exp.DType.NVARCHAR: "VARCHAR", 264 exp.DType.INET: "INET", 265 exp.DType.ROWVERSION: "VARBINARY", 266 exp.DType.UBIGINT: "BIGINT", 267 exp.DType.UINT: "INT", 268 exp.DType.UMEDIUMINT: "MEDIUMINT", 269 exp.DType.USMALLINT: "SMALLINT", 270 exp.DType.UTINYINT: "TINYINT", 271 exp.DType.UDECIMAL: "DECIMAL", 272 exp.DType.UDOUBLE: "DOUBLE", 273 exp.DType.DATETIME2: "DATETIME", 274 exp.DType.SMALLDATETIME: "DATETIME", 275 exp.DType.TIMESTAMP: "DATETIME", 276 exp.DType.TIMESTAMPNTZ: "DATETIME", 277 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 278 exp.DType.TIMESTAMPLTZ: "TIMESTAMP", 279 } 280 281 PROPERTIES_LOCATION: t.ClassVar = { 282 **generator.Generator.PROPERTIES_LOCATION, 283 exp.TransientProperty: exp.Properties.Location.UNSUPPORTED, 284 exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED, 285 exp.PartitionedByProperty: exp.Properties.Location.UNSUPPORTED, 286 exp.PartitionByRangeProperty: exp.Properties.Location.POST_SCHEMA, 287 exp.PartitionByListProperty: exp.Properties.Location.POST_SCHEMA, 288 exp.Property: exp.Properties.Location.POST_SCHEMA, 289 } 290 291 LIMIT_FETCH = "LIMIT" 292 293 LIMIT_ONLY_LITERALS = True 294 295 CHAR_CAST_MAPPING: t.ClassVar = dict.fromkeys( 296 ( 297 exp.DType.LONGTEXT, 298 exp.DType.LONGBLOB, 299 exp.DType.MEDIUMBLOB, 300 exp.DType.MEDIUMTEXT, 301 exp.DType.TEXT, 302 exp.DType.TINYBLOB, 303 exp.DType.TINYTEXT, 304 exp.DType.VARCHAR, 305 ), 306 "CHAR", 307 ) 308 SIGNED_CAST_MAPPING: t.ClassVar = dict.fromkeys( 309 ( 310 exp.DType.BIGINT, 311 exp.DType.BOOLEAN, 312 exp.DType.INT, 313 exp.DType.SMALLINT, 314 exp.DType.TINYINT, 315 exp.DType.MEDIUMINT, 316 ), 317 "SIGNED", 318 ) 319 320 # MySQL doesn't support many datatypes in cast. 321 # https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html#function_cast 322 CAST_MAPPING: t.ClassVar = { 323 exp.DType.LONGTEXT: "CHAR", 324 exp.DType.LONGBLOB: "CHAR", 325 exp.DType.MEDIUMBLOB: "CHAR", 326 exp.DType.MEDIUMTEXT: "CHAR", 327 exp.DType.TEXT: "CHAR", 328 exp.DType.TINYBLOB: "CHAR", 329 exp.DType.TINYTEXT: "CHAR", 330 exp.DType.VARCHAR: "CHAR", 331 exp.DType.BIGINT: "SIGNED", 332 exp.DType.BOOLEAN: "SIGNED", 333 exp.DType.INT: "SIGNED", 334 exp.DType.SMALLINT: "SIGNED", 335 exp.DType.TINYINT: "SIGNED", 336 exp.DType.MEDIUMINT: "SIGNED", 337 exp.DType.UBIGINT: "UNSIGNED", 338 } 339 340 TIMESTAMP_FUNC_TYPES: t.ClassVar = { 341 exp.DType.TIMESTAMPTZ, 342 exp.DType.TIMESTAMPLTZ, 343 } 344 345 # https://dev.mysql.com/doc/refman/8.0/en/keywords.html 346 RESERVED_KEYWORDS = { 347 "accessible", 348 "add", 349 "all", 350 "alter", 351 "analyze", 352 "and", 353 "as", 354 "asc", 355 "asensitive", 356 "before", 357 "between", 358 "bigint", 359 "binary", 360 "blob", 361 "both", 362 "by", 363 "call", 364 "cascade", 365 "case", 366 "change", 367 "char", 368 "character", 369 "check", 370 "collate", 371 "column", 372 "condition", 373 "constraint", 374 "continue", 375 "convert", 376 "create", 377 "cross", 378 "cube", 379 "cume_dist", 380 "current_date", 381 "current_time", 382 "current_timestamp", 383 "current_user", 384 "cursor", 385 "database", 386 "databases", 387 "day_hour", 388 "day_microsecond", 389 "day_minute", 390 "day_second", 391 "dec", 392 "decimal", 393 "declare", 394 "default", 395 "delayed", 396 "delete", 397 "dense_rank", 398 "desc", 399 "describe", 400 "deterministic", 401 "distinct", 402 "distinctrow", 403 "div", 404 "double", 405 "drop", 406 "dual", 407 "each", 408 "else", 409 "elseif", 410 "empty", 411 "enclosed", 412 "escaped", 413 "except", 414 "exists", 415 "exit", 416 "explain", 417 "false", 418 "fetch", 419 "first_value", 420 "float", 421 "float4", 422 "float8", 423 "for", 424 "force", 425 "foreign", 426 "from", 427 "fulltext", 428 "function", 429 "generated", 430 "get", 431 "grant", 432 "group", 433 "grouping", 434 "groups", 435 "having", 436 "high_priority", 437 "hour_microsecond", 438 "hour_minute", 439 "hour_second", 440 "if", 441 "ignore", 442 "in", 443 "index", 444 "infile", 445 "inner", 446 "inout", 447 "insensitive", 448 "insert", 449 "int", 450 "int1", 451 "int2", 452 "int3", 453 "int4", 454 "int8", 455 "integer", 456 "intersect", 457 "interval", 458 "into", 459 "io_after_gtids", 460 "io_before_gtids", 461 "is", 462 "iterate", 463 "join", 464 "json_table", 465 "key", 466 "keys", 467 "kill", 468 "lag", 469 "last_value", 470 "lateral", 471 "lead", 472 "leading", 473 "leave", 474 "left", 475 "like", 476 "limit", 477 "linear", 478 "lines", 479 "load", 480 "localtime", 481 "localtimestamp", 482 "lock", 483 "long", 484 "longblob", 485 "longtext", 486 "loop", 487 "low_priority", 488 "master_bind", 489 "master_ssl_verify_server_cert", 490 "match", 491 "maxvalue", 492 "mediumblob", 493 "mediumint", 494 "mediumtext", 495 "middleint", 496 "minute_microsecond", 497 "minute_second", 498 "mod", 499 "modifies", 500 "natural", 501 "not", 502 "no_write_to_binlog", 503 "nth_value", 504 "ntile", 505 "null", 506 "numeric", 507 "of", 508 "on", 509 "optimize", 510 "optimizer_costs", 511 "option", 512 "optionally", 513 "or", 514 "order", 515 "out", 516 "outer", 517 "outfile", 518 "over", 519 "partition", 520 "percent_rank", 521 "precision", 522 "primary", 523 "procedure", 524 "purge", 525 "range", 526 "rank", 527 "read", 528 "reads", 529 "read_write", 530 "real", 531 "recursive", 532 "references", 533 "regexp", 534 "release", 535 "rename", 536 "repeat", 537 "replace", 538 "require", 539 "resignal", 540 "restrict", 541 "return", 542 "revoke", 543 "right", 544 "rlike", 545 "row", 546 "rows", 547 "row_number", 548 "schema", 549 "schemas", 550 "second_microsecond", 551 "select", 552 "sensitive", 553 "separator", 554 "set", 555 "show", 556 "signal", 557 "smallint", 558 "spatial", 559 "specific", 560 "sql", 561 "sqlexception", 562 "sqlstate", 563 "sqlwarning", 564 "sql_big_result", 565 "sql_calc_found_rows", 566 "sql_small_result", 567 "ssl", 568 "starting", 569 "stored", 570 "straight_join", 571 "system", 572 "table", 573 "terminated", 574 "then", 575 "tinyblob", 576 "tinyint", 577 "tinytext", 578 "to", 579 "trailing", 580 "trigger", 581 "true", 582 "undo", 583 "union", 584 "unique", 585 "unlock", 586 "unsigned", 587 "update", 588 "usage", 589 "use", 590 "using", 591 "utc_date", 592 "utc_time", 593 "utc_timestamp", 594 "values", 595 "varbinary", 596 "varchar", 597 "varcharacter", 598 "varying", 599 "virtual", 600 "when", 601 "where", 602 "while", 603 "window", 604 "with", 605 "write", 606 "xor", 607 "year_month", 608 "zerofill", 609 } 610 611 SQL_SECURITY_VIEW_LOCATION: t.ClassVar = exp.Properties.Location.POST_CREATE 612 613 def makeinterval_sql(self: MySQLGenerator, expression: exp.MakeInterval) -> str: 614 intervals: list[exp.Interval] = [] 615 for arg_key, value in expression.args.items(): 616 if value is None: 617 continue 618 619 if isinstance(value, exp.Kwarg): 620 unit_name = _MAKE_INTERVAL_UNIT_ALIASES.get( 621 value.this.name.lower(), value.this.name.lower() 622 ) 623 value = value.expression 624 else: 625 unit_name = arg_key 626 627 intervals.append(exp.Interval(this=value.copy(), unit=exp.var(unit_name.upper()))) 628 629 if not intervals: 630 return self.function_fallback_sql(expression) 631 632 parent = expression.parent 633 sep = " - " if isinstance(parent, exp.Sub) and parent.expression is expression else " + " 634 635 return sep.join(self.sql(interval) for interval in intervals) 636 637 def locate_properties(self, properties: exp.Properties) -> defaultdict: 638 locations = super().locate_properties(properties) 639 640 # MySQL puts SQL SECURITY before VIEW but after the schema for functions/procedures 641 if isinstance(create := properties.parent, exp.Create) and create.kind == "VIEW": 642 post_schema = locations[exp.Properties.Location.POST_SCHEMA] 643 for i, p in enumerate(post_schema): 644 if isinstance(p, exp.SqlSecurityProperty): 645 post_schema.pop(i) 646 locations[self.SQL_SECURITY_VIEW_LOCATION].append(p) 647 break 648 649 return locations 650 651 def computedcolumnconstraint_sql(self, expression: exp.ComputedColumnConstraint) -> str: 652 persisted = "STORED" if expression.args.get("persisted") else "VIRTUAL" 653 return f"GENERATED ALWAYS AS ({self.sql(expression.this.unnest())}) {persisted}" 654 655 def array_sql(self, expression: exp.Array) -> str: 656 self.unsupported("Arrays are not supported by MySQL") 657 return self.function_fallback_sql(expression) 658 659 def arraycontainsall_sql(self, expression: exp.ArrayContainsAll) -> str: 660 self.unsupported("Array operations are not supported by MySQL") 661 return self.function_fallback_sql(expression) 662 663 def arraycontainedby_sql(self, expression: exp.ArrayContainedBy) -> str: 664 self.unsupported("Array operations are not supported by MySQL") 665 return self.function_fallback_sql(expression) 666 667 def dpipe_sql(self, expression: exp.DPipe) -> str: 668 return self.func("CONCAT", *expression.flatten()) 669 670 def intdiv_sql(self, expression: exp.IntDiv) -> str: 671 this = self.sql(exp._wrap(expression.this, exp.Binary)) 672 divisor = self.sql(exp._wrap(expression.expression, exp.Binary)) 673 sql = f"{this} {self.maybe_comment('DIV', comments=expression.comments)} {divisor}" 674 675 parent = expression.parent 676 if isinstance(parent, (exp.Neg, exp.BitwiseNot)) or ( 677 isinstance(parent, (exp.Mul, exp.Div, exp.IntDiv, exp.Mod)) 678 and parent.expression is expression 679 ): 680 return f"({sql})" 681 682 return sql 683 684 def extract_sql(self, expression: exp.Extract) -> str: 685 unit = expression.name 686 if unit and unit.lower() == "epoch": 687 return self.func("UNIX_TIMESTAMP", expression.expression) 688 689 return super().extract_sql(expression) 690 691 def datatype_sql(self, expression: exp.DataType) -> str: 692 if ( 693 self.VARCHAR_REQUIRES_SIZE 694 and expression.is_type(exp.DType.VARCHAR) 695 and not expression.expressions 696 ): 697 # `VARCHAR` must always have a size - if it doesn't, we always generate `TEXT` 698 return "TEXT" 699 700 # https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html 701 result = super().datatype_sql(expression) 702 if expression.this in self.UNSIGNED_TYPE_MAPPING: 703 result = f"{result} UNSIGNED" 704 705 return result 706 707 def jsonarraycontains_sql(self, expression: exp.JSONArrayContains) -> str: 708 return f"{self.sql(expression, 'this')} MEMBER OF({self.sql(expression, 'expression')})" 709 710 def cast_sql(self, expression: exp.Cast, safe_prefix: str | None = None) -> str: 711 if expression.to.this in self.TIMESTAMP_FUNC_TYPES: 712 return self.func("TIMESTAMP", expression.this) 713 714 to = self.CAST_MAPPING.get(expression.to.this) 715 716 if to: 717 expression.to.set("this", to) 718 return super().cast_sql(expression) 719 720 def show_sql(self, expression: exp.Show) -> str: 721 this = f" {expression.name}" 722 full = " FULL" if expression.args.get("full") else "" 723 global_ = " GLOBAL" if expression.args.get("global_") else "" 724 725 target = self.sql(expression, "target") 726 727 # SHOW CREATE ... takes a possibly qualified name, it has no FROM clause 728 # https://dev.mysql.com/doc/refman/8.4/en/show-create-table.html 729 if expression.name.startswith("CREATE") and (db_id := self.sql(expression, "db")): 730 target = f"{db_id}.{target}" 731 db = "" 732 else: 733 db = self._prefixed_sql("FROM", expression, "db") 734 735 target = f" {target}" if target else "" 736 if expression.name in ("COLUMNS", "INDEX"): 737 target = f" FROM{target}" 738 elif expression.name == "GRANTS": 739 target = f" FOR{target}" 740 elif expression.name in ("LINKS", "PARTITIONS"): 741 target = f" ON{target}" if target else "" 742 elif expression.name == "PROJECTIONS": 743 target = f" ON TABLE{target}" if target else "" 744 745 like = self._prefixed_sql("LIKE", expression, "like") 746 where = self.sql(expression, "where") 747 748 types = self.expressions(expression, key="types") 749 types = f" {types}" if types else types 750 query = self._prefixed_sql("FOR QUERY", expression, "query") 751 752 if expression.name == "PROFILE": 753 offset = self._prefixed_sql("OFFSET", expression, "offset") 754 limit = self._prefixed_sql("LIMIT", expression, "limit") 755 else: 756 offset = "" 757 limit = self._oldstyle_limit_sql(expression) 758 759 log = self._prefixed_sql("IN", expression, "log") 760 position = self._prefixed_sql("FROM", expression, "position") 761 762 channel = self._prefixed_sql("FOR CHANNEL", expression, "channel") 763 764 if expression.name == "ENGINE": 765 mutex_or_status = " MUTEX" if expression.args.get("mutex") else " STATUS" 766 else: 767 mutex_or_status = "" 768 769 for_table = self._prefixed_sql("FOR TABLE", expression, "for_table") 770 for_group = self._prefixed_sql("FOR GROUP", expression, "for_group") 771 for_user = self._prefixed_sql("FOR USER", expression, "for_user") 772 for_role = self._prefixed_sql("FOR ROLE", expression, "for_role") 773 into_outfile = self._prefixed_sql("INTO OUTFILE", expression, "into_outfile") 774 json = " JSON" if expression.args.get("json") else "" 775 776 return f"SHOW{full}{global_}{this}{json}{target}{for_table}{types}{db}{query}{log}{position}{channel}{mutex_or_status}{like}{where}{offset}{limit}{for_group}{for_user}{for_role}{into_outfile}" 777 778 def alterrename_sql(self, expression: exp.AlterRename, include_to: bool = True) -> str: 779 """To avoid TO keyword in ALTER ... RENAME statements. 780 It's moved from Doris, because it's the same for all MySQL, Doris, and StarRocks. 781 """ 782 return super().alterrename_sql(expression, include_to=False) 783 784 def altercolumn_sql(self, expression: exp.AlterColumn) -> str: 785 dtype = self.sql(expression, "dtype") 786 if not dtype: 787 return super().altercolumn_sql(expression) 788 789 if expression.args.get("exists"): 790 self.unsupported("ALTER COLUMN IF EXISTS is not supported by this dialect") 791 792 this = self.sql(expression, "this") 793 null_constraint = self._alter_column_null_constraint_sql(expression) 794 return f"MODIFY COLUMN {this} {dtype}{null_constraint}" 795 796 def _prefixed_sql(self, prefix: str, expression: exp.Expr, arg: str) -> str: 797 sql = self.sql(expression, arg) 798 return f" {prefix} {sql}" if sql else "" 799 800 def _oldstyle_limit_sql(self, expression: exp.Show) -> str: 801 limit = self.sql(expression, "limit") 802 offset = self.sql(expression, "offset") 803 if limit: 804 limit_offset = f"{offset}, {limit}" if offset else limit 805 return f" LIMIT {limit_offset}" 806 return "" 807 808 def timestamptrunc_sql(self, expression: exp.TimestampTrunc) -> str: 809 unit = expression.args.get("unit") 810 if isinstance(unit, exp.WeekStart): 811 unit = exp.var(self.weekstart_name(unit)) 812 813 # Pick an old-enough date to avoid negative timestamp diffs 814 start_ts = "'0000-01-01 00:00:00'" 815 816 # Source: https://stackoverflow.com/a/32955740 817 timestamp_diff = build_date_delta(exp.TimestampDiff)([unit, start_ts, expression.this]) 818 interval = exp.Interval(this=timestamp_diff, unit=unit) 819 dateadd = build_date_delta_with_interval(exp.DateAdd)([start_ts, interval]) 820 821 return self.sql(dateadd) 822 823 def converttimezone_sql(self, expression: exp.ConvertTimezone) -> str: 824 from_tz = expression.args.get("source_tz") 825 to_tz = expression.args.get("target_tz") 826 dt = expression.args.get("timestamp") 827 828 return self.func("CONVERT_TZ", dt, from_tz, to_tz) 829 830 def attimezone_sql(self, expression: exp.AtTimeZone) -> str: 831 self.unsupported("AT TIME ZONE is not supported by MySQL") 832 return self.sql(expression.this) 833 834 def isascii_sql(self, expression: exp.IsAscii) -> str: 835 return f"REGEXP_LIKE({self.sql(expression.this)}, '^[[:ascii:]]*$')" 836 837 def ignorenulls_sql(self, expression: exp.IgnoreNulls) -> str: 838 # https://dev.mysql.com/doc/refman/8.4/en/window-function-descriptions.html 839 self.unsupported("MySQL does not support IGNORE NULLS.") 840 return self.sql(expression.this) 841 842 @unsupported_args("this") 843 def currentschema_sql(self, expression: exp.CurrentSchema) -> str: 844 return self.func("SCHEMA") 845 846 def partition_sql(self, expression: exp.Partition) -> str: 847 parent = expression.parent 848 if isinstance(parent, (exp.PartitionByRangeProperty, exp.PartitionByListProperty)): 849 return self.expressions(expression, flat=True) 850 return super().partition_sql(expression) 851 852 def _partition_by_sql( 853 self, expression: exp.PartitionByRangeProperty | exp.PartitionByListProperty, kind: str 854 ) -> str: 855 partitions = self.expressions(expression, key="partition_expressions", flat=True) 856 create = self.expressions(expression, key="create_expressions", flat=True) 857 return f"PARTITION BY {kind} ({partitions}) ({create})" 858 859 def partitionbyrangeproperty_sql(self, expression: exp.PartitionByRangeProperty) -> str: 860 return self._partition_by_sql(expression, "RANGE") 861 862 def partitionbylistproperty_sql(self, expression: exp.PartitionByListProperty) -> str: 863 return self._partition_by_sql(expression, "LIST") 864 865 def partitionlist_sql(self, expression: exp.PartitionList) -> str: 866 name = self.sql(expression, "this") 867 values = self.expressions(expression, flat=True) 868 return f"PARTITION {name} VALUES IN ({values})" 869 870 def partitionrange_sql(self, expression: exp.PartitionRange) -> str: 871 name = self.sql(expression, "this") 872 values = self.expressions(expression, flat=True) 873 return f"PARTITION {name} VALUES LESS THAN ({values})"
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
ALTER_PARTITION_OPTIONS: ClassVar[tuple[type[sqlglot.expressions.core.Expr], ...]] =
(<class 'sqlglot.expressions.properties.PartitionByListProperty'>, <class 'sqlglot.expressions.properties.PartitionByRangeProperty'>)
TRANSFORMS =
{<class 'sqlglot.expressions.query.JSONPathFilter'>: <function <lambda>>, <class 'sqlglot.expressions.query.JSONPathKey'>: <function <lambda>>, <class 'sqlglot.expressions.query.JSONPathRecursive'>: <function <lambda>>, <class 'sqlglot.expressions.query.JSONPathRoot'>: <function <lambda>>, <class 'sqlglot.expressions.query.JSONPathScript'>: <function <lambda>>, <class 'sqlglot.expressions.query.JSONPathSelector'>: <function <lambda>>, <class 'sqlglot.expressions.query.JSONPathSlice'>: <function <lambda>>, <class 'sqlglot.expressions.query.JSONPathSubscript'>: <function <lambda>>, <class 'sqlglot.expressions.query.JSONPathUnion'>: <function <lambda>>, <class 'sqlglot.expressions.query.JSONPathWildcard'>: <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.ArrayContainedBy'>: <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.BinaryColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CaseSpecificColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CalledOnNullInputProperty'>: <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 MySQLGenerator.<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 Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONBContainsAnyTopKeys'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONBContainsAllTopKeys'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONBContainsTopKey'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONBDeleteAtPath'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONBPathExists'>: <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 Generator.<lambda>>, <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 Generator.<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 rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.UtcTimestamp'>: <function rename_func.<locals>.<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.aggregate.ArrayAgg'>: <function rename_func.<locals>.<lambda>>, <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.Chr'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.CurrentDate'>: <function no_paren_current_date_sql>, <class 'sqlglot.expressions.functions.CurrentVersion'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.DateDiff'>: <function remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.temporal.DateAdd'>: <function date_add_sql.<locals>.func>, <class 'sqlglot.expressions.temporal.DateStrToDate'>: <function datestrtodate_sql>, <class 'sqlglot.expressions.temporal.DateSub'>: <function date_add_sql.<locals>.func>, <class 'sqlglot.expressions.temporal.DateTrunc'>: <function _date_trunc_sql>, <class 'sqlglot.expressions.temporal.Day'>: <function remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.temporal.DayOfMonth'>: <function remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.temporal.DayOfWeek'>: <function remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.temporal.DayOfYear'>: <function remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.aggregate.GroupConcat'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.core.ILike'>: <function no_ilike_sql>, <class 'sqlglot.expressions.functions.If'>: <function if_sql.<locals>._if_sql>, <class 'sqlglot.expressions.json.JSONExtractScalar'>: <function arrow_json_extract_sql>, <class 'sqlglot.expressions.string.Length'>: <function length_or_char_length_sql>, <class 'sqlglot.expressions.aggregate.LogicalOr'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.aggregate.LogicalAnd'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.aggregate.Max'>: <function max_or_greatest>, <class 'sqlglot.expressions.aggregate.Min'>: <function min_or_least>, <class 'sqlglot.expressions.temporal.Month'>: <function remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.core.NullSafeEQ'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.core.NullSafeNEQ'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.string.NumberToStr'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.query.Pivot'>: <function no_pivot_sql>, <class 'sqlglot.expressions.query.Select'>: <function preprocess.<locals>._to_sql>, <class 'sqlglot.expressions.aggregate.Stddev'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.string.StrPosition'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.StrToDate'>: <function _str_to_date_sql>, <class 'sqlglot.expressions.temporal.StrToTime'>: <function _str_to_date_sql>, <class 'sqlglot.expressions.string.Stuff'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.query.TableSample'>: <function no_tablesample_sql>, <class 'sqlglot.expressions.temporal.TimeFromParts'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.TimestampAdd'>: <function date_add_interval_sql.<locals>.func>, <class 'sqlglot.expressions.temporal.TimestampDiff'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.TimestampSub'>: <function date_add_interval_sql.<locals>.func>, <class 'sqlglot.expressions.temporal.TimeStrToUnix'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.TimeStrToTime'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.TimeToStr'>: <function remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.string.Trim'>: <function trim_sql>, <class 'sqlglot.expressions.math.Trunc'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.functions.TryCast'>: <function no_trycast_sql>, <class 'sqlglot.expressions.temporal.TsOrDsAdd'>: <function date_add_sql.<locals>.func>, <class 'sqlglot.expressions.temporal.TsOrDsDiff'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.TsOrDsToDate'>: <function _ts_or_ds_to_date_sql>, <class 'sqlglot.expressions.string.Unicode'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.UnixToTime'>: <function _unix_to_time_sql>, <class 'sqlglot.expressions.aggregate.Variance'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.aggregate.VariancePop'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.Week'>: <function remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.temporal.WeekOfYear'>: <function remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.temporal.Year'>: <function remove_ts_or_ds_to_date.<locals>.func>}
UNSIGNED_TYPE_MAPPING: ClassVar =
{<DType.UBIGINT: 'UBIGINT'>: 'BIGINT', <DType.UINT: 'UINT'>: 'INT', <DType.UMEDIUMINT: 'UMEDIUMINT'>: 'MEDIUMINT', <DType.USMALLINT: 'USMALLINT'>: 'SMALLINT', <DType.UTINYINT: 'UTINYINT'>: 'TINYINT', <DType.UDECIMAL: 'UDECIMAL'>: 'DECIMAL', <DType.UDOUBLE: 'UDOUBLE'>: 'DOUBLE'}
TIMESTAMP_TYPE_MAPPING: ClassVar =
{<DType.DATETIME2: 'DATETIME2'>: 'DATETIME', <DType.SMALLDATETIME: 'SMALLDATETIME'>: 'DATETIME', <DType.TIMESTAMP: 'TIMESTAMP'>: 'DATETIME', <DType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>: 'DATETIME', <DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>: 'TIMESTAMP', <DType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>: 'TIMESTAMP'}
TYPE_MAPPING: ClassVar =
{<DType.NCHAR: 'NCHAR'>: 'CHAR', <DType.NVARCHAR: 'NVARCHAR'>: 'VARCHAR', <DType.INET: 'INET'>: 'INET', <DType.ROWVERSION: 'ROWVERSION'>: 'VARBINARY', <DType.UBIGINT: 'UBIGINT'>: 'BIGINT', <DType.UINT: 'UINT'>: 'INT', <DType.UMEDIUMINT: 'UMEDIUMINT'>: 'MEDIUMINT', <DType.USMALLINT: 'USMALLINT'>: 'SMALLINT', <DType.UTINYINT: 'UTINYINT'>: 'TINYINT', <DType.UDECIMAL: 'UDECIMAL'>: 'DECIMAL', <DType.UDOUBLE: 'UDOUBLE'>: 'DOUBLE', <DType.DATETIME2: 'DATETIME2'>: 'DATETIME', <DType.SMALLDATETIME: 'SMALLDATETIME'>: 'DATETIME', <DType.TIMESTAMP: 'TIMESTAMP'>: 'DATETIME', <DType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>: 'DATETIME', <DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>: 'TIMESTAMP', <DType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>: 'TIMESTAMP'}
PROPERTIES_LOCATION: ClassVar =
{<class 'sqlglot.expressions.properties.AggregateKeyProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <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.CalledOnNullInputProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <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.ClusterProperty'>: <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.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.PartitionedOfProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.PhysicalProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.constraints.PrimaryKey'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.Property'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <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.StorageProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <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.TableSpaceProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <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.UNSUPPORTED: 'UNSUPPORTED'>, <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'>, <class 'sqlglot.expressions.properties.PartitionByRangeProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.PartitionByListProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>}
CHAR_CAST_MAPPING: ClassVar =
{<DType.LONGTEXT: 'LONGTEXT'>: 'CHAR', <DType.LONGBLOB: 'LONGBLOB'>: 'CHAR', <DType.MEDIUMBLOB: 'MEDIUMBLOB'>: 'CHAR', <DType.MEDIUMTEXT: 'MEDIUMTEXT'>: 'CHAR', <DType.TEXT: 'TEXT'>: 'CHAR', <DType.TINYBLOB: 'TINYBLOB'>: 'CHAR', <DType.TINYTEXT: 'TINYTEXT'>: 'CHAR', <DType.VARCHAR: 'VARCHAR'>: 'CHAR'}
SIGNED_CAST_MAPPING: ClassVar =
{<DType.BIGINT: 'BIGINT'>: 'SIGNED', <DType.BOOLEAN: 'BOOLEAN'>: 'SIGNED', <DType.INT: 'INT'>: 'SIGNED', <DType.SMALLINT: 'SMALLINT'>: 'SIGNED', <DType.TINYINT: 'TINYINT'>: 'SIGNED', <DType.MEDIUMINT: 'MEDIUMINT'>: 'SIGNED'}
CAST_MAPPING: ClassVar =
{<DType.LONGTEXT: 'LONGTEXT'>: 'CHAR', <DType.LONGBLOB: 'LONGBLOB'>: 'CHAR', <DType.MEDIUMBLOB: 'MEDIUMBLOB'>: 'CHAR', <DType.MEDIUMTEXT: 'MEDIUMTEXT'>: 'CHAR', <DType.TEXT: 'TEXT'>: 'CHAR', <DType.TINYBLOB: 'TINYBLOB'>: 'CHAR', <DType.TINYTEXT: 'TINYTEXT'>: 'CHAR', <DType.VARCHAR: 'VARCHAR'>: 'CHAR', <DType.BIGINT: 'BIGINT'>: 'SIGNED', <DType.BOOLEAN: 'BOOLEAN'>: 'SIGNED', <DType.INT: 'INT'>: 'SIGNED', <DType.SMALLINT: 'SMALLINT'>: 'SIGNED', <DType.TINYINT: 'TINYINT'>: 'SIGNED', <DType.MEDIUMINT: 'MEDIUMINT'>: 'SIGNED', <DType.UBIGINT: 'UBIGINT'>: 'UNSIGNED'}
TIMESTAMP_FUNC_TYPES: ClassVar =
{<DType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>}
RESERVED_KEYWORDS =
{'optimize', 'outfile', 'low_priority', 'check', 'int', 'ignore', 'tinyint', 'character', 'where', 'json_table', 'distinct', 'group', 'null', 'key', 'using', 'delete', 'generated', 'numeric', 'show', 'undo', 'unsigned', 'foreign', 'unlock', 'lock', 'optimizer_costs', 'high_priority', 'union', 'trailing', 'as', 'hour_second', 'except', 'minute_microsecond', 'sql_small_result', 'by', 'cross', 'hour_minute', 'natural', 'groups', 'master_bind', 'hour_microsecond', 'ntile', 'last_value', 'day_second', 'schemas', 'load', 'trigger', 'cube', 'constraint', 'window', 'loop', 'not', 'no_write_to_binlog', 'localtime', 'sensitive', 'declare', 'percent_rank', 'exit', 'is', 'precision', 'use', 'int4', 'day_hour', 'asensitive', 'column', 'int1', 'then', 'require', 'if', 'match', 'keys', 'with', 'databases', 'add', 'each', 'middleint', 'update', 'int8', 'continue', 'sqlstate', 'smallint', 'grouping', 'terminated', 'div', 'analyze', 'false', 'ssl', 'binary', 'mediumblob', 'sql', 'call', 'primary', 'delayed', 'left', 'fulltext', 'else', 'case', 'enclosed', 'longtext', 'sql_big_result', 'desc', 'all', 'intersect', 'float', 'both', 'limit', 'database', 'recursive', 'elseif', 'or', 'io_before_gtids', 'create', 'deterministic', 'row_number', 'real', 'explain', 'current_timestamp', 'current_user', 'longblob', 'function', 'read_write', 'lead', 'optionally', 'usage', 'order', 'localtimestamp', 'grant', 'tinytext', 'dual', 'day_microsecond', 'first_value', 'stored', 'asc', 'signal', 'restrict', 'exists', 'index', 'range', 'utc_date', 'references', 'cascade', 'out', 'condition', 'varcharacter', 'repeat', 'purge', 'empty', 'char', 'outer', 'describe', 'mediumtext', 'maxvalue', 'distinctrow', 'starting', 'of', 'read', 'regexp', 'virtual', 'and', 'on', 'when', 'mediumint', 'rename', 'lines', 'option', 'accessible', 'xor', 'drop', 'decimal', 'double', 'float4', 'year_month', 'between', 'to', 'specific', 'set', 'zerofill', 'integer', 'dense_rank', 'io_after_gtids', 'over', 'interval', 'mod', 'reads', 'change', 'like', 'current_date', 'procedure', 'int2', 'return', 'before', 'partition', 'table', 'schema', 'bigint', 'varbinary', 'second_microsecond', 'minute_second', 'while', 'in', 'write', 'into', 'release', 'true', 'int3', 'rows', 'revoke', 'varchar', 'infile', 'rank', 'fetch', 'dec', 'resignal', 'inner', 'nth_value', 'leading', 'utc_time', 'leave', 'current_time', 'collate', 'unique', 'varying', 'values', 'blob', 'get', 'cursor', 'day_minute', 'sqlexception', 'insert', 'for', 'insensitive', 'sqlwarning', 'from', 'select', 'default', 'master_ssl_verify_server_cert', 'inout', 'having', 'lag', 'rlike', 'straight_join', 'alter', 'kill', 'right', 'separator', 'lateral', 'float8', 'cume_dist', 'row', 'utc_timestamp', 'convert', 'tinyblob', 'iterate', 'sql_calc_found_rows', 'replace', 'spatial', 'linear', 'modifies', 'join', 'long', 'escaped', 'system', 'force'}
def
makeinterval_sql( self: MySQLGenerator, expression: sqlglot.expressions.temporal.MakeInterval) -> str:
613 def makeinterval_sql(self: MySQLGenerator, expression: exp.MakeInterval) -> str: 614 intervals: list[exp.Interval] = [] 615 for arg_key, value in expression.args.items(): 616 if value is None: 617 continue 618 619 if isinstance(value, exp.Kwarg): 620 unit_name = _MAKE_INTERVAL_UNIT_ALIASES.get( 621 value.this.name.lower(), value.this.name.lower() 622 ) 623 value = value.expression 624 else: 625 unit_name = arg_key 626 627 intervals.append(exp.Interval(this=value.copy(), unit=exp.var(unit_name.upper()))) 628 629 if not intervals: 630 return self.function_fallback_sql(expression) 631 632 parent = expression.parent 633 sep = " - " if isinstance(parent, exp.Sub) and parent.expression is expression else " + " 634 635 return sep.join(self.sql(interval) for interval in intervals)
def
locate_properties( self, properties: sqlglot.expressions.properties.Properties) -> collections.defaultdict:
637 def locate_properties(self, properties: exp.Properties) -> defaultdict: 638 locations = super().locate_properties(properties) 639 640 # MySQL puts SQL SECURITY before VIEW but after the schema for functions/procedures 641 if isinstance(create := properties.parent, exp.Create) and create.kind == "VIEW": 642 post_schema = locations[exp.Properties.Location.POST_SCHEMA] 643 for i, p in enumerate(post_schema): 644 if isinstance(p, exp.SqlSecurityProperty): 645 post_schema.pop(i) 646 locations[self.SQL_SECURITY_VIEW_LOCATION].append(p) 647 break 648 649 return locations
def
computedcolumnconstraint_sql( self, expression: sqlglot.expressions.constraints.ComputedColumnConstraint) -> str:
670 def intdiv_sql(self, expression: exp.IntDiv) -> str: 671 this = self.sql(exp._wrap(expression.this, exp.Binary)) 672 divisor = self.sql(exp._wrap(expression.expression, exp.Binary)) 673 sql = f"{this} {self.maybe_comment('DIV', comments=expression.comments)} {divisor}" 674 675 parent = expression.parent 676 if isinstance(parent, (exp.Neg, exp.BitwiseNot)) or ( 677 isinstance(parent, (exp.Mul, exp.Div, exp.IntDiv, exp.Mod)) 678 and parent.expression is expression 679 ): 680 return f"({sql})" 681 682 return sql
691 def datatype_sql(self, expression: exp.DataType) -> str: 692 if ( 693 self.VARCHAR_REQUIRES_SIZE 694 and expression.is_type(exp.DType.VARCHAR) 695 and not expression.expressions 696 ): 697 # `VARCHAR` must always have a size - if it doesn't, we always generate `TEXT` 698 return "TEXT" 699 700 # https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html 701 result = super().datatype_sql(expression) 702 if expression.this in self.UNSIGNED_TYPE_MAPPING: 703 result = f"{result} UNSIGNED" 704 705 return result
def
cast_sql( self, expression: sqlglot.expressions.functions.Cast, safe_prefix: str | None = None) -> str:
710 def cast_sql(self, expression: exp.Cast, safe_prefix: str | None = None) -> str: 711 if expression.to.this in self.TIMESTAMP_FUNC_TYPES: 712 return self.func("TIMESTAMP", expression.this) 713 714 to = self.CAST_MAPPING.get(expression.to.this) 715 716 if to: 717 expression.to.set("this", to) 718 return super().cast_sql(expression)
720 def show_sql(self, expression: exp.Show) -> str: 721 this = f" {expression.name}" 722 full = " FULL" if expression.args.get("full") else "" 723 global_ = " GLOBAL" if expression.args.get("global_") else "" 724 725 target = self.sql(expression, "target") 726 727 # SHOW CREATE ... takes a possibly qualified name, it has no FROM clause 728 # https://dev.mysql.com/doc/refman/8.4/en/show-create-table.html 729 if expression.name.startswith("CREATE") and (db_id := self.sql(expression, "db")): 730 target = f"{db_id}.{target}" 731 db = "" 732 else: 733 db = self._prefixed_sql("FROM", expression, "db") 734 735 target = f" {target}" if target else "" 736 if expression.name in ("COLUMNS", "INDEX"): 737 target = f" FROM{target}" 738 elif expression.name == "GRANTS": 739 target = f" FOR{target}" 740 elif expression.name in ("LINKS", "PARTITIONS"): 741 target = f" ON{target}" if target else "" 742 elif expression.name == "PROJECTIONS": 743 target = f" ON TABLE{target}" if target else "" 744 745 like = self._prefixed_sql("LIKE", expression, "like") 746 where = self.sql(expression, "where") 747 748 types = self.expressions(expression, key="types") 749 types = f" {types}" if types else types 750 query = self._prefixed_sql("FOR QUERY", expression, "query") 751 752 if expression.name == "PROFILE": 753 offset = self._prefixed_sql("OFFSET", expression, "offset") 754 limit = self._prefixed_sql("LIMIT", expression, "limit") 755 else: 756 offset = "" 757 limit = self._oldstyle_limit_sql(expression) 758 759 log = self._prefixed_sql("IN", expression, "log") 760 position = self._prefixed_sql("FROM", expression, "position") 761 762 channel = self._prefixed_sql("FOR CHANNEL", expression, "channel") 763 764 if expression.name == "ENGINE": 765 mutex_or_status = " MUTEX" if expression.args.get("mutex") else " STATUS" 766 else: 767 mutex_or_status = "" 768 769 for_table = self._prefixed_sql("FOR TABLE", expression, "for_table") 770 for_group = self._prefixed_sql("FOR GROUP", expression, "for_group") 771 for_user = self._prefixed_sql("FOR USER", expression, "for_user") 772 for_role = self._prefixed_sql("FOR ROLE", expression, "for_role") 773 into_outfile = self._prefixed_sql("INTO OUTFILE", expression, "into_outfile") 774 json = " JSON" if expression.args.get("json") else "" 775 776 return f"SHOW{full}{global_}{this}{json}{target}{for_table}{types}{db}{query}{log}{position}{channel}{mutex_or_status}{like}{where}{offset}{limit}{for_group}{for_user}{for_role}{into_outfile}"
def
alterrename_sql( self, expression: sqlglot.expressions.ddl.AlterRename, include_to: bool = True) -> str:
778 def alterrename_sql(self, expression: exp.AlterRename, include_to: bool = True) -> str: 779 """To avoid TO keyword in ALTER ... RENAME statements. 780 It's moved from Doris, because it's the same for all MySQL, Doris, and StarRocks. 781 """ 782 return super().alterrename_sql(expression, include_to=False)
To avoid TO keyword in ALTER ... RENAME statements. It's moved from Doris, because it's the same for all MySQL, Doris, and StarRocks.
784 def altercolumn_sql(self, expression: exp.AlterColumn) -> str: 785 dtype = self.sql(expression, "dtype") 786 if not dtype: 787 return super().altercolumn_sql(expression) 788 789 if expression.args.get("exists"): 790 self.unsupported("ALTER COLUMN IF EXISTS is not supported by this dialect") 791 792 this = self.sql(expression, "this") 793 null_constraint = self._alter_column_null_constraint_sql(expression) 794 return f"MODIFY COLUMN {this} {dtype}{null_constraint}"
808 def timestamptrunc_sql(self, expression: exp.TimestampTrunc) -> str: 809 unit = expression.args.get("unit") 810 if isinstance(unit, exp.WeekStart): 811 unit = exp.var(self.weekstart_name(unit)) 812 813 # Pick an old-enough date to avoid negative timestamp diffs 814 start_ts = "'0000-01-01 00:00:00'" 815 816 # Source: https://stackoverflow.com/a/32955740 817 timestamp_diff = build_date_delta(exp.TimestampDiff)([unit, start_ts, expression.this]) 818 interval = exp.Interval(this=timestamp_diff, unit=unit) 819 dateadd = build_date_delta_with_interval(exp.DateAdd)([start_ts, interval]) 820 821 return self.sql(dateadd)
@unsupported_args('this')
def
currentschema_sql(self, expression: sqlglot.expressions.functions.CurrentSchema) -> str:
def
partitionbyrangeproperty_sql( self, expression: sqlglot.expressions.properties.PartitionByRangeProperty) -> str:
def
partitionbylistproperty_sql( self, expression: sqlglot.expressions.properties.PartitionByListProperty) -> str:
Inherited Members
- sqlglot.generator.Generator
- Generator
- WINDOW_FUNCS_WITH_NULL_ORDERING
- IGNORE_NULLS_IN_FUNC
- IGNORE_NULLS_BEFORE_ORDER
- EXCEPT_INTERSECT_SUPPORT_ALL_CLAUSE
- CREATE_FUNCTION_RETURN_AS
- MATCHED_BY_SOURCE
- SUPPORTS_MERGE_WHERE
- SINGLE_STRING_INTERVAL
- AUTO_REFRESH_BARE_INTERVALS
- RENAME_TABLE_WITH_DB
- GROUPINGS_SEP
- SUPPORTS_GROUPING_SETS_AS_SUFFIX
- INDEX_ON
- INOUT_SEPARATOR
- DIRECTED_JOINS
- QUERY_HINTS
- IS_BOOL_ALLOWED
- SAFE_INT_DIVISION
- LIMIT_IS_TOP
- RETURNING_END
- EXTRACT_ALLOWS_QUOTES
- TZ_TO_WITH_TIME_ZONE
- ALTER_TABLE_INCLUDE_COLUMN_KEYWORD
- UNNEST_WITH_ORDINALITY
- 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
- HISTORICAL_DATA_POST_ALIAS
- COLLATE_IS_FUNC
- DATA_TYPE_SPECIFIERS_ALLOWED
- ENSURE_BOOLS
- CTE_RECURSIVE_KEYWORD_REQUIRED
- SUPPORTS_SINGLE_ARG_CONCAT
- SUPPORTS_TABLE_ALIAS_COLUMNS
- SUPPORTS_NAMED_CTE_COLUMNS
- UNPIVOT_ALIASES_ARE_IDENTIFIERS
- PIVOT_ALIAS_WITH_AS
- INSERT_OVERWRITE
- SUPPORTS_SELECT_INTO
- SUPPORTS_UNLOGGED_TABLES
- SUPPORTS_CREATE_TABLE_LIKE
- SUPPORTS_ALTER_COLUMN_IF_EXISTS
- LIKE_PROPERTY_INSIDE_SCHEMA
- MULTI_ARG_DISTINCT
- JSON_PATH_SINGLE_QUOTE_ESCAPE
- JSON_PATH_KEY_QUOTED_FORCES_BRACKETS
- SUPPORTED_JSON_PATH_PARTS
- CAN_IMPLEMENT_ARRAY_ANY
- SUPPORTS_WINDOW_EXCLUDE
- SET_OP_MODIFIERS
- SET_OP_LIMITS
- SET_OP_PARENTHESIZED_OPERANDS
- COPY_PARAMS_ARE_WRAPPED
- COPY_PARAMS_EQ_REQUIRED
- COPY_HAS_INTO_KEYWORD
- UNICODE_SUBSTITUTE
- STAR_EXCEPT
- HEX_FUNC
- WITH_PROPERTIES_PREFIX
- QUOTE_JSON_PATH
- SUPPORTS_EXPLODING_PROJECTIONS
- ARRAY_CONCAT_IS_VAR_LEN
- SUPPORTS_CONVERT_TIMEZONE
- SUPPORTS_UNIX_SECONDS
- ALTER_SET_WRAPPED
- NORMALIZE_EXTRACT_DATE_PARTS
- 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
- DECLARE_DEFAULT_ASSIGNMENT
- STAR_EXCLUDE_REQUIRES_DERIVED_TABLE
- SUPPORTS_DROP_ALTER_ICEBERG_PROPERTY
- UNSUPPORTED_TYPES
- TYPE_PARAM_SETTINGS
- TIME_PART_SINGULARS
- TOKEN_MAPPING
- STRUCT_DELIMITER
- PARAMETER_TOKEN
- NAMED_PLACEHOLDER_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
- MOD_OPERATOR
- MOD_PAREN_PARENT_TYPES
- SAFE_JSON_PATH_KEY_RE
- 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_parts
- column_sql
- pseudocolumn_sql
- columnposition_sql
- columndef_sql
- columnconstraint_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_param_bound_limiter
- directory_sql
- delete_sql
- drop_sql
- set_operation
- set_operations
- fetch_sql
- limitoptions_sql
- filter_sql
- hint_sql
- indexparameters_sql
- index_sql
- dynamicidentifier_sql
- identifier_sql
- hex_sql
- lowerhex_sql
- inputoutputformat_sql
- national_sql
- properties_sql
- root_properties
- properties
- with_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
- lockingstatement_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_parts
- table_sql
- tablefromrows_sql
- tablesample_sql
- pivot_sql
- version_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
- clusterproperty_sql
- distribute_sql
- sort_sql
- ordered_sql
- matchrecognizemeasure_sql
- matchrecognize_sql
- query_modifiers
- options_modifier
- forclause_sql
- 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
- partitionbyexcluding_sql
- windowspec_sql
- withingroup_sql
- between_sql
- bracket_offset_expressions
- bracket_sql
- all_sql
- any_sql
- exists_sql
- case_sql
- constraint_sql
- nextvaluefor_sql
- trim_sql
- convert_concat_args
- concat_sql
- concatws_sql
- check_sql
- foreignkey_sql
- primarykey_sql
- timeserieskey_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
- in_unnest_op
- interval_sql
- return_sql
- reference_sql
- anonymous_sql
- paren_sql
- neg_sql
- not_sql
- alias_sql
- pivotalias_sql
- aliases_sql
- atindex_sql
- fromtimezone_sql
- fromiso8601date_sql
- fromiso8601timestamp_sql
- fromiso8601timestampnanos_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
- strtodate_sql
- parsedatetime_sql
- currentdate_sql
- collate_sql
- command_sql
- comment_sql
- mergetreettlaction_sql
- mergetreettl_sql
- transaction_sql
- commit_sql
- rollback_sql
- modifycolumn_sql
- alterindex_sql
- alterdiststyle_sql
- altersortkey_sql
- renamecolumn_sql
- alterset_sql
- alter_sql
- altersession_sql
- add_column_sql
- droppartition_sql
- dropprimarykey_sql
- addconstraint_sql
- replacecolumns_sql
- addpartition_sql
- distinct_sql
- respectnulls_sql
- havingmax_sql
- div_sql
- safedivide_sql
- overlaps_sql
- distance_sql
- distancend_sql
- dot_sql
- eq_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
- mod_sql
- mul_sql
- neq_sql
- nullsafeeq_sql
- nullsafeneq_sql
- sub_sql
- trycast_sql
- jsoncast_sql
- try_sql
- log_sql
- use_sql
- binary
- ceil_floor
- function_fallback_sql
- function_name
- func
- format_args
- too_wide
- format_time
- expressions
- op_expressions
- naked_property
- tag_sql
- token_sql
- userdefinedfunction_sql
- macrooverloads_sql
- macrooverload_sql
- joinhint_sql
- kwarg_sql
- when_sql
- whens_sql
- merge_sql
- tochar_sql
- tonumber_sql
- dictproperty_sql
- dictrange_sql
- dictsubproperty_sql
- aggregatekeyproperty_sql
- duplicatekeyproperty_sql
- uniquekeyproperty_sql
- distributedbyproperty_sql
- oncluster_sql
- clusteredbyproperty_sql
- anyvalue_sql
- querytransform_sql
- indexconstraintoption_sql
- checkcolumnconstraint_sql
- indexcolumnconstraint_sql
- nvl2_sql
- nthvalue_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
- arrayinsert_sql
- arrayany_sql
- struct_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
- 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
- arraysort_sql
- arraysize_sql
- attach_sql
- detach_sql
- attachoption_sql
- watermarkcolumnconstraint_sql
- encodeproperty_sql
- includeproperty_sql
- xmlelement_sql
- xmlkeyvalueoption_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
- install_sql
- liststage_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_name
- weekstart_sql
- chr_sql
- weightstring_sql
- block_sql
- functionspecification_sql
- storedprocedure_sql
- ifblock_sql
- casestatement_sql
- whileblock_sql
- loopblock_sql
- repeatblock_sql
- leave_sql
- iterate_sql
- execute_sql
- executesql_sql
- altermodifysqlsecurity_sql
- usingproperty_sql
- renameindex_sql