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 rename_func, 21 strposition_sql, 22 unit_to_var, 23 trim_sql, 24 timestrtotime_sql, 25) 26from sqlglot.generator import unsupported_args 27from collections import defaultdict 28 29 30def _date_trunc_sql(self: MySQLGenerator, expression: exp.DateTrunc) -> str: 31 expr = self.sql(expression, "this") 32 unit = expression.text("unit").upper() 33 34 if unit == "WEEK": 35 concat = f"CONCAT(YEAR({expr}), ' ', WEEK({expr}, 1), ' 1')" 36 date_format = "%Y %u %w" 37 elif unit == "MONTH": 38 concat = f"CONCAT(YEAR({expr}), ' ', MONTH({expr}), ' 1')" 39 date_format = "%Y %c %e" 40 elif unit == "QUARTER": 41 concat = f"CONCAT(YEAR({expr}), ' ', QUARTER({expr}) * 3 - 2, ' 1')" 42 date_format = "%Y %c %e" 43 elif unit == "YEAR": 44 concat = f"CONCAT(YEAR({expr}), ' 1 1')" 45 date_format = "%Y %c %e" 46 else: 47 if unit != "DAY": 48 self.unsupported(f"Unexpected interval unit: {unit}") 49 return self.func("DATE", expr) 50 51 return self.func("STR_TO_DATE", concat, f"'{date_format}'") 52 53 54def _str_to_date_sql( 55 self: MySQLGenerator, expression: exp.StrToDate | exp.StrToTime | exp.TsOrDsToDate 56) -> str: 57 return self.func("STR_TO_DATE", expression.this, self.format_time(expression)) 58 59 60def _unix_to_time_sql(self: MySQLGenerator, expression: exp.UnixToTime) -> str: 61 scale = expression.args.get("scale") 62 timestamp = expression.this 63 64 if scale in (None, exp.UnixToTime.SECONDS): 65 return self.func("FROM_UNIXTIME", timestamp, self.format_time(expression)) 66 67 return self.func( 68 "FROM_UNIXTIME", 69 exp.Div(this=timestamp, expression=exp.func("POW", 10, scale)), 70 self.format_time(expression), 71 ) 72 73 74def date_add_sql( 75 kind: str, 76) -> t.Callable[[generator.Generator, exp.Expr], str]: 77 def func(self: generator.Generator, expression: exp.Expr) -> str: 78 return self.func( 79 f"DATE_{kind}", 80 expression.this, 81 exp.Interval(this=expression.expression, unit=unit_to_var(expression)), 82 ) 83 84 return func 85 86 87def _ts_or_ds_to_date_sql(self: MySQLGenerator, expression: exp.TsOrDsToDate) -> str: 88 time_format = expression.args.get("format") 89 return _str_to_date_sql(self, expression) if time_format else self.func("DATE", expression.this) 90 91 92def _remove_ts_or_ds_to_date( 93 to_sql: t.Callable[[MySQLGenerator, exp.Expr], str] | None = None, 94 args: tuple[str, ...] = ("this",), 95) -> t.Callable[[MySQLGenerator, exp.Func], str]: 96 def func(self: MySQLGenerator, expression: exp.Func) -> str: 97 for arg_key in args: 98 arg = expression.args.get(arg_key) 99 if isinstance(arg, (exp.TsOrDsToDate, exp.TsOrDsToTimestamp)) and not arg.args.get( 100 "format" 101 ): 102 expression.set(arg_key, arg.this) 103 104 return to_sql(self, expression) if to_sql else self.function_fallback_sql(expression) 105 106 return func 107 108 109class MySQLGenerator(generator.Generator): 110 SELECT_KINDS: tuple[str, ...] = () 111 TRY_SUPPORTED = False 112 SUPPORTS_UESCAPE = False 113 SUPPORTS_DECODE_CASE = False 114 SUPPORTS_MODIFY_COLUMN = True 115 SUPPORTS_CHANGE_COLUMN = True 116 117 AFTER_HAVING_MODIFIER_TRANSFORMS = generator.AFTER_HAVING_MODIFIER_TRANSFORMS 118 119 INTERVAL_ALLOWS_PLURAL_FORM = False 120 LOCKING_READS_SUPPORTED = True 121 NULL_ORDERING_SUPPORTED: bool | None = None 122 JOIN_HINTS = False 123 TABLE_HINTS = True 124 DUPLICATE_KEY_UPDATE_WITH_SET = False 125 QUERY_HINT_SEP = " " 126 VALUES_AS_TABLE = False 127 NVL2_SUPPORTED = False 128 LAST_DAY_SUPPORTS_DATE_PART = False 129 JSON_TYPE_REQUIRED_FOR_EXTRACTION = True 130 JSON_PATH_BRACKETED_KEY_SUPPORTED = False 131 JSON_KEY_VALUE_PAIR_SEP = "," 132 SUPPORTS_TO_NUMBER = False 133 PARSE_JSON_NAME: str | None = None 134 PAD_FILL_PATTERN_IS_REQUIRED = True 135 WRAP_DERIVED_VALUES = False 136 VARCHAR_REQUIRES_SIZE = True 137 SUPPORTS_MEDIAN = False 138 UPDATE_STATEMENT_SUPPORTS_FROM = False 139 140 TRANSFORMS = { 141 **generator.Generator.TRANSFORMS, 142 exp.ArrayAgg: rename_func("GROUP_CONCAT"), 143 exp.BitwiseAndAgg: rename_func("BIT_AND"), 144 exp.BitwiseOrAgg: rename_func("BIT_OR"), 145 exp.BitwiseXorAgg: rename_func("BIT_XOR"), 146 exp.BitwiseCount: rename_func("BIT_COUNT"), 147 exp.Chr: lambda self, e: self.chr_sql(e, "CHAR"), 148 exp.CurrentDate: no_paren_current_date_sql, 149 exp.CurrentVersion: rename_func("VERSION"), 150 exp.DateDiff: _remove_ts_or_ds_to_date( 151 lambda self, e: self.func("DATEDIFF", e.this, e.expression), ("this", "expression") 152 ), 153 exp.DateAdd: _remove_ts_or_ds_to_date(date_add_sql("ADD")), 154 exp.DateStrToDate: datestrtodate_sql, 155 exp.DateSub: _remove_ts_or_ds_to_date(date_add_sql("SUB")), 156 exp.DateTrunc: _date_trunc_sql, 157 exp.Day: _remove_ts_or_ds_to_date(), 158 exp.DayOfMonth: _remove_ts_or_ds_to_date(rename_func("DAYOFMONTH")), 159 exp.DayOfWeek: _remove_ts_or_ds_to_date(rename_func("DAYOFWEEK")), 160 exp.DayOfYear: _remove_ts_or_ds_to_date(rename_func("DAYOFYEAR")), 161 exp.GroupConcat: lambda self, e: ( 162 f"""GROUP_CONCAT({self.sql(e, "this")} SEPARATOR {self.sql(e, "separator") or "','"})""" 163 ), 164 exp.ILike: no_ilike_sql, 165 exp.JSONExtractScalar: arrow_json_extract_sql, 166 exp.Length: length_or_char_length_sql, 167 exp.LogicalOr: rename_func("MAX"), 168 exp.LogicalAnd: rename_func("MIN"), 169 exp.Max: max_or_greatest, 170 exp.Min: min_or_least, 171 exp.Month: _remove_ts_or_ds_to_date(), 172 exp.NullSafeEQ: lambda self, e: self.binary(e, "<=>"), 173 exp.NullSafeNEQ: lambda self, e: f"NOT {self.binary(e, '<=>')}", 174 exp.NumberToStr: rename_func("FORMAT"), 175 exp.Pivot: no_pivot_sql, 176 exp.Select: transforms.preprocess( 177 [ 178 transforms.eliminate_distinct_on, 179 transforms.eliminate_semi_and_anti_joins, 180 transforms.eliminate_qualify, 181 transforms.eliminate_full_outer_join, 182 transforms.unnest_generate_date_array_using_recursive_cte, 183 ] 184 ), 185 exp.StrPosition: lambda self, e: strposition_sql( 186 self, e, func_name="LOCATE", supports_position=True 187 ), 188 exp.StrToDate: _str_to_date_sql, 189 exp.StrToTime: _str_to_date_sql, 190 exp.Stuff: rename_func("INSERT"), 191 exp.SessionUser: lambda *_: "SESSION_USER()", 192 exp.TableSample: no_tablesample_sql, 193 exp.TimeFromParts: rename_func("MAKETIME"), 194 exp.TimestampAdd: date_add_interval_sql("DATE", "ADD"), 195 exp.TimestampDiff: lambda self, e: self.func( 196 "TIMESTAMPDIFF", unit_to_var(e), e.expression, e.this 197 ), 198 exp.TimestampSub: date_add_interval_sql("DATE", "SUB"), 199 exp.TimeStrToUnix: rename_func("UNIX_TIMESTAMP"), 200 exp.TimeStrToTime: lambda self, e: timestrtotime_sql( 201 self, 202 e, 203 include_precision=not e.args.get("zone"), 204 ), 205 exp.TimeToStr: _remove_ts_or_ds_to_date( 206 lambda self, e: self.func("DATE_FORMAT", e.this, self.format_time(e)) 207 ), 208 exp.Trim: trim_sql, 209 exp.Trunc: rename_func("TRUNCATE"), 210 exp.TryCast: no_trycast_sql, 211 exp.TsOrDsAdd: date_add_sql("ADD"), 212 exp.TsOrDsDiff: lambda self, e: self.func("DATEDIFF", e.this, e.expression), 213 exp.TsOrDsToDate: _ts_or_ds_to_date_sql, 214 exp.Unicode: lambda self, e: f"ORD(CONVERT({self.sql(e.this)} USING utf32))", 215 exp.UnixToTime: _unix_to_time_sql, 216 exp.Week: _remove_ts_or_ds_to_date(), 217 exp.WeekOfYear: _remove_ts_or_ds_to_date(rename_func("WEEKOFYEAR")), 218 exp.Year: _remove_ts_or_ds_to_date(), 219 exp.UtcTimestamp: rename_func("UTC_TIMESTAMP"), 220 exp.UtcTime: rename_func("UTC_TIME"), 221 } 222 223 UNSIGNED_TYPE_MAPPING = { 224 exp.DType.UBIGINT: "BIGINT", 225 exp.DType.UINT: "INT", 226 exp.DType.UMEDIUMINT: "MEDIUMINT", 227 exp.DType.USMALLINT: "SMALLINT", 228 exp.DType.UTINYINT: "TINYINT", 229 exp.DType.UDECIMAL: "DECIMAL", 230 exp.DType.UDOUBLE: "DOUBLE", 231 } 232 233 TIMESTAMP_TYPE_MAPPING = { 234 exp.DType.DATETIME2: "DATETIME", 235 exp.DType.SMALLDATETIME: "DATETIME", 236 exp.DType.TIMESTAMP: "DATETIME", 237 exp.DType.TIMESTAMPNTZ: "DATETIME", 238 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 239 exp.DType.TIMESTAMPLTZ: "TIMESTAMP", 240 } 241 242 TYPE_MAPPING: t.ClassVar = { 243 exp.DType.NCHAR: "CHAR", 244 exp.DType.NVARCHAR: "VARCHAR", 245 exp.DType.INET: "INET", 246 exp.DType.ROWVERSION: "VARBINARY", 247 exp.DType.UBIGINT: "BIGINT", 248 exp.DType.UINT: "INT", 249 exp.DType.UMEDIUMINT: "MEDIUMINT", 250 exp.DType.USMALLINT: "SMALLINT", 251 exp.DType.UTINYINT: "TINYINT", 252 exp.DType.UDECIMAL: "DECIMAL", 253 exp.DType.UDOUBLE: "DOUBLE", 254 exp.DType.DATETIME2: "DATETIME", 255 exp.DType.SMALLDATETIME: "DATETIME", 256 exp.DType.TIMESTAMP: "DATETIME", 257 exp.DType.TIMESTAMPNTZ: "DATETIME", 258 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 259 exp.DType.TIMESTAMPLTZ: "TIMESTAMP", 260 } 261 262 PROPERTIES_LOCATION: t.ClassVar = { 263 **generator.Generator.PROPERTIES_LOCATION, 264 exp.TransientProperty: exp.Properties.Location.UNSUPPORTED, 265 exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED, 266 exp.PartitionedByProperty: exp.Properties.Location.UNSUPPORTED, 267 exp.PartitionByRangeProperty: exp.Properties.Location.POST_SCHEMA, 268 exp.PartitionByListProperty: exp.Properties.Location.POST_SCHEMA, 269 } 270 271 LIMIT_FETCH = "LIMIT" 272 273 LIMIT_ONLY_LITERALS = True 274 275 CHAR_CAST_MAPPING: t.ClassVar = dict.fromkeys( 276 ( 277 exp.DType.LONGTEXT, 278 exp.DType.LONGBLOB, 279 exp.DType.MEDIUMBLOB, 280 exp.DType.MEDIUMTEXT, 281 exp.DType.TEXT, 282 exp.DType.TINYBLOB, 283 exp.DType.TINYTEXT, 284 exp.DType.VARCHAR, 285 ), 286 "CHAR", 287 ) 288 SIGNED_CAST_MAPPING: t.ClassVar = dict.fromkeys( 289 ( 290 exp.DType.BIGINT, 291 exp.DType.BOOLEAN, 292 exp.DType.INT, 293 exp.DType.SMALLINT, 294 exp.DType.TINYINT, 295 exp.DType.MEDIUMINT, 296 ), 297 "SIGNED", 298 ) 299 300 # MySQL doesn't support many datatypes in cast. 301 # https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html#function_cast 302 CAST_MAPPING = { 303 exp.DType.LONGTEXT: "CHAR", 304 exp.DType.LONGBLOB: "CHAR", 305 exp.DType.MEDIUMBLOB: "CHAR", 306 exp.DType.MEDIUMTEXT: "CHAR", 307 exp.DType.TEXT: "CHAR", 308 exp.DType.TINYBLOB: "CHAR", 309 exp.DType.TINYTEXT: "CHAR", 310 exp.DType.VARCHAR: "CHAR", 311 exp.DType.BIGINT: "SIGNED", 312 exp.DType.BOOLEAN: "SIGNED", 313 exp.DType.INT: "SIGNED", 314 exp.DType.SMALLINT: "SIGNED", 315 exp.DType.TINYINT: "SIGNED", 316 exp.DType.MEDIUMINT: "SIGNED", 317 exp.DType.UBIGINT: "UNSIGNED", 318 } 319 320 TIMESTAMP_FUNC_TYPES = { 321 exp.DType.TIMESTAMPTZ, 322 exp.DType.TIMESTAMPLTZ, 323 } 324 325 # https://dev.mysql.com/doc/refman/8.0/en/keywords.html 326 RESERVED_KEYWORDS = { 327 "accessible", 328 "add", 329 "all", 330 "alter", 331 "analyze", 332 "and", 333 "as", 334 "asc", 335 "asensitive", 336 "before", 337 "between", 338 "bigint", 339 "binary", 340 "blob", 341 "both", 342 "by", 343 "call", 344 "cascade", 345 "case", 346 "change", 347 "char", 348 "character", 349 "check", 350 "collate", 351 "column", 352 "condition", 353 "constraint", 354 "continue", 355 "convert", 356 "create", 357 "cross", 358 "cube", 359 "cume_dist", 360 "current_date", 361 "current_time", 362 "current_timestamp", 363 "current_user", 364 "cursor", 365 "database", 366 "databases", 367 "day_hour", 368 "day_microsecond", 369 "day_minute", 370 "day_second", 371 "dec", 372 "decimal", 373 "declare", 374 "default", 375 "delayed", 376 "delete", 377 "dense_rank", 378 "desc", 379 "describe", 380 "deterministic", 381 "distinct", 382 "distinctrow", 383 "div", 384 "double", 385 "drop", 386 "dual", 387 "each", 388 "else", 389 "elseif", 390 "empty", 391 "enclosed", 392 "escaped", 393 "except", 394 "exists", 395 "exit", 396 "explain", 397 "false", 398 "fetch", 399 "first_value", 400 "float", 401 "float4", 402 "float8", 403 "for", 404 "force", 405 "foreign", 406 "from", 407 "fulltext", 408 "function", 409 "generated", 410 "get", 411 "grant", 412 "group", 413 "grouping", 414 "groups", 415 "having", 416 "high_priority", 417 "hour_microsecond", 418 "hour_minute", 419 "hour_second", 420 "if", 421 "ignore", 422 "in", 423 "index", 424 "infile", 425 "inner", 426 "inout", 427 "insensitive", 428 "insert", 429 "int", 430 "int1", 431 "int2", 432 "int3", 433 "int4", 434 "int8", 435 "integer", 436 "intersect", 437 "interval", 438 "into", 439 "io_after_gtids", 440 "io_before_gtids", 441 "is", 442 "iterate", 443 "join", 444 "json_table", 445 "key", 446 "keys", 447 "kill", 448 "lag", 449 "last_value", 450 "lateral", 451 "lead", 452 "leading", 453 "leave", 454 "left", 455 "like", 456 "limit", 457 "linear", 458 "lines", 459 "load", 460 "localtime", 461 "localtimestamp", 462 "lock", 463 "long", 464 "longblob", 465 "longtext", 466 "loop", 467 "low_priority", 468 "master_bind", 469 "master_ssl_verify_server_cert", 470 "match", 471 "maxvalue", 472 "mediumblob", 473 "mediumint", 474 "mediumtext", 475 "middleint", 476 "minute_microsecond", 477 "minute_second", 478 "mod", 479 "modifies", 480 "natural", 481 "not", 482 "no_write_to_binlog", 483 "nth_value", 484 "ntile", 485 "null", 486 "numeric", 487 "of", 488 "on", 489 "optimize", 490 "optimizer_costs", 491 "option", 492 "optionally", 493 "or", 494 "order", 495 "out", 496 "outer", 497 "outfile", 498 "over", 499 "partition", 500 "percent_rank", 501 "precision", 502 "primary", 503 "procedure", 504 "purge", 505 "range", 506 "rank", 507 "read", 508 "reads", 509 "read_write", 510 "real", 511 "recursive", 512 "references", 513 "regexp", 514 "release", 515 "rename", 516 "repeat", 517 "replace", 518 "require", 519 "resignal", 520 "restrict", 521 "return", 522 "revoke", 523 "right", 524 "rlike", 525 "row", 526 "rows", 527 "row_number", 528 "schema", 529 "schemas", 530 "second_microsecond", 531 "select", 532 "sensitive", 533 "separator", 534 "set", 535 "show", 536 "signal", 537 "smallint", 538 "spatial", 539 "specific", 540 "sql", 541 "sqlexception", 542 "sqlstate", 543 "sqlwarning", 544 "sql_big_result", 545 "sql_calc_found_rows", 546 "sql_small_result", 547 "ssl", 548 "starting", 549 "stored", 550 "straight_join", 551 "system", 552 "table", 553 "terminated", 554 "then", 555 "tinyblob", 556 "tinyint", 557 "tinytext", 558 "to", 559 "trailing", 560 "trigger", 561 "true", 562 "undo", 563 "union", 564 "unique", 565 "unlock", 566 "unsigned", 567 "update", 568 "usage", 569 "use", 570 "using", 571 "utc_date", 572 "utc_time", 573 "utc_timestamp", 574 "values", 575 "varbinary", 576 "varchar", 577 "varcharacter", 578 "varying", 579 "virtual", 580 "when", 581 "where", 582 "while", 583 "window", 584 "with", 585 "write", 586 "xor", 587 "year_month", 588 "zerofill", 589 } 590 591 SQL_SECURITY_VIEW_LOCATION = exp.Properties.Location.POST_CREATE 592 593 def locate_properties(self, properties: exp.Properties) -> defaultdict: 594 locations = super().locate_properties(properties) 595 596 # MySQL puts SQL SECURITY before VIEW but after the schema for functions/procedures 597 if isinstance(create := properties.parent, exp.Create) and create.kind == "VIEW": 598 post_schema = locations[exp.Properties.Location.POST_SCHEMA] 599 for i, p in enumerate(post_schema): 600 if isinstance(p, exp.SqlSecurityProperty): 601 post_schema.pop(i) 602 locations[self.SQL_SECURITY_VIEW_LOCATION].append(p) 603 break 604 605 return locations 606 607 def computedcolumnconstraint_sql(self, expression: exp.ComputedColumnConstraint) -> str: 608 persisted = "STORED" if expression.args.get("persisted") else "VIRTUAL" 609 return f"GENERATED ALWAYS AS ({self.sql(expression.this.unnest())}) {persisted}" 610 611 def array_sql(self, expression: exp.Array) -> str: 612 self.unsupported("Arrays are not supported by MySQL") 613 return self.function_fallback_sql(expression) 614 615 def arraycontainsall_sql(self, expression: exp.ArrayContainsAll) -> str: 616 self.unsupported("Array operations are not supported by MySQL") 617 return self.function_fallback_sql(expression) 618 619 def dpipe_sql(self, expression: exp.DPipe) -> str: 620 return self.func("CONCAT", *expression.flatten()) 621 622 def extract_sql(self, expression: exp.Extract) -> str: 623 unit = expression.name 624 if unit and unit.lower() == "epoch": 625 return self.func("UNIX_TIMESTAMP", expression.expression) 626 627 return super().extract_sql(expression) 628 629 def datatype_sql(self, expression: exp.DataType) -> str: 630 if ( 631 self.VARCHAR_REQUIRES_SIZE 632 and expression.is_type(exp.DType.VARCHAR) 633 and not expression.expressions 634 ): 635 # `VARCHAR` must always have a size - if it doesn't, we always generate `TEXT` 636 return "TEXT" 637 638 # https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html 639 result = super().datatype_sql(expression) 640 if expression.this in self.UNSIGNED_TYPE_MAPPING: 641 result = f"{result} UNSIGNED" 642 643 return result 644 645 def jsonarraycontains_sql(self, expression: exp.JSONArrayContains) -> str: 646 return f"{self.sql(expression, 'this')} MEMBER OF({self.sql(expression, 'expression')})" 647 648 def cast_sql(self, expression: exp.Cast, safe_prefix: str | None = None) -> str: 649 if expression.to.this in self.TIMESTAMP_FUNC_TYPES: 650 return self.func("TIMESTAMP", expression.this) 651 652 to = self.CAST_MAPPING.get(expression.to.this) 653 654 if to: 655 expression.to.set("this", to) 656 return super().cast_sql(expression) 657 658 def show_sql(self, expression: exp.Show) -> str: 659 this = f" {expression.name}" 660 full = " FULL" if expression.args.get("full") else "" 661 global_ = " GLOBAL" if expression.args.get("global_") else "" 662 663 target = self.sql(expression, "target") 664 target = f" {target}" if target else "" 665 if expression.name in ("COLUMNS", "INDEX"): 666 target = f" FROM{target}" 667 elif expression.name == "GRANTS": 668 target = f" FOR{target}" 669 elif expression.name in ("LINKS", "PARTITIONS"): 670 target = f" ON{target}" if target else "" 671 elif expression.name == "PROJECTIONS": 672 target = f" ON TABLE{target}" if target else "" 673 674 db = self._prefixed_sql("FROM", expression, "db") 675 676 like = self._prefixed_sql("LIKE", expression, "like") 677 where = self.sql(expression, "where") 678 679 types = self.expressions(expression, key="types") 680 types = f" {types}" if types else types 681 query = self._prefixed_sql("FOR QUERY", expression, "query") 682 683 if expression.name == "PROFILE": 684 offset = self._prefixed_sql("OFFSET", expression, "offset") 685 limit = self._prefixed_sql("LIMIT", expression, "limit") 686 else: 687 offset = "" 688 limit = self._oldstyle_limit_sql(expression) 689 690 log = self._prefixed_sql("IN", expression, "log") 691 position = self._prefixed_sql("FROM", expression, "position") 692 693 channel = self._prefixed_sql("FOR CHANNEL", expression, "channel") 694 695 if expression.name == "ENGINE": 696 mutex_or_status = " MUTEX" if expression.args.get("mutex") else " STATUS" 697 else: 698 mutex_or_status = "" 699 700 for_table = self._prefixed_sql("FOR TABLE", expression, "for_table") 701 for_group = self._prefixed_sql("FOR GROUP", expression, "for_group") 702 for_user = self._prefixed_sql("FOR USER", expression, "for_user") 703 for_role = self._prefixed_sql("FOR ROLE", expression, "for_role") 704 into_outfile = self._prefixed_sql("INTO OUTFILE", expression, "into_outfile") 705 json = " JSON" if expression.args.get("json") else "" 706 707 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}" 708 709 def alterrename_sql(self, expression: exp.AlterRename, include_to: bool = True) -> str: 710 """To avoid TO keyword in ALTER ... RENAME statements. 711 It's moved from Doris, because it's the same for all MySQL, Doris, and StarRocks. 712 """ 713 return super().alterrename_sql(expression, include_to=False) 714 715 def altercolumn_sql(self, expression: exp.AlterColumn) -> str: 716 dtype = self.sql(expression, "dtype") 717 if not dtype: 718 return super().altercolumn_sql(expression) 719 720 this = self.sql(expression, "this") 721 return f"MODIFY COLUMN {this} {dtype}" 722 723 def _prefixed_sql(self, prefix: str, expression: exp.Expr, arg: str) -> str: 724 sql = self.sql(expression, arg) 725 return f" {prefix} {sql}" if sql else "" 726 727 def _oldstyle_limit_sql(self, expression: exp.Show) -> str: 728 limit = self.sql(expression, "limit") 729 offset = self.sql(expression, "offset") 730 if limit: 731 limit_offset = f"{offset}, {limit}" if offset else limit 732 return f" LIMIT {limit_offset}" 733 return "" 734 735 def timestamptrunc_sql(self, expression: exp.TimestampTrunc) -> str: 736 unit = expression.args.get("unit") 737 738 # Pick an old-enough date to avoid negative timestamp diffs 739 start_ts = "'0000-01-01 00:00:00'" 740 741 # Source: https://stackoverflow.com/a/32955740 742 timestamp_diff = build_date_delta(exp.TimestampDiff)([unit, start_ts, expression.this]) 743 interval = exp.Interval(this=timestamp_diff, unit=unit) 744 dateadd = build_date_delta_with_interval(exp.DateAdd)([start_ts, interval]) 745 746 return self.sql(dateadd) 747 748 def converttimezone_sql(self, expression: exp.ConvertTimezone) -> str: 749 from_tz = expression.args.get("source_tz") 750 to_tz = expression.args.get("target_tz") 751 dt = expression.args.get("timestamp") 752 753 return self.func("CONVERT_TZ", dt, from_tz, to_tz) 754 755 def attimezone_sql(self, expression: exp.AtTimeZone) -> str: 756 self.unsupported("AT TIME ZONE is not supported by MySQL") 757 return self.sql(expression.this) 758 759 def isascii_sql(self, expression: exp.IsAscii) -> str: 760 return f"REGEXP_LIKE({self.sql(expression.this)}, '^[[:ascii:]]*$')" 761 762 def ignorenulls_sql(self, expression: exp.IgnoreNulls) -> str: 763 # https://dev.mysql.com/doc/refman/8.4/en/window-function-descriptions.html 764 self.unsupported("MySQL does not support IGNORE NULLS.") 765 return self.sql(expression.this) 766 767 @unsupported_args("this") 768 def currentschema_sql(self, expression: exp.CurrentSchema) -> str: 769 return self.func("SCHEMA") 770 771 def partition_sql(self, expression: exp.Partition) -> str: 772 parent = expression.parent 773 if isinstance(parent, (exp.PartitionByRangeProperty, exp.PartitionByListProperty)): 774 return self.expressions(expression, flat=True) 775 return super().partition_sql(expression) 776 777 def _partition_by_sql( 778 self, expression: exp.PartitionByRangeProperty | exp.PartitionByListProperty, kind: str 779 ) -> str: 780 partitions = self.expressions(expression, key="partition_expressions", flat=True) 781 create = self.expressions(expression, key="create_expressions", flat=True) 782 return f"PARTITION BY {kind} ({partitions}) ({create})" 783 784 def partitionbyrangeproperty_sql(self, expression: exp.PartitionByRangeProperty) -> str: 785 return self._partition_by_sql(expression, "RANGE") 786 787 def partitionbylistproperty_sql(self, expression: exp.PartitionByListProperty) -> str: 788 return self._partition_by_sql(expression, "LIST") 789 790 def partitionlist_sql(self, expression: exp.PartitionList) -> str: 791 name = self.sql(expression, "this") 792 values = self.expressions(expression, flat=True) 793 return f"PARTITION {name} VALUES IN ({values})" 794 795 def partitionrange_sql(self, expression: exp.PartitionRange) -> str: 796 name = self.sql(expression, "this") 797 values = self.expressions(expression, flat=True) 798 return f"PARTITION {name} VALUES LESS THAN ({values})"
def
date_add_sql( kind: str) -> Callable[[sqlglot.generator.Generator, sqlglot.expressions.core.Expr], str]:
75def date_add_sql( 76 kind: str, 77) -> t.Callable[[generator.Generator, exp.Expr], str]: 78 def func(self: generator.Generator, expression: exp.Expr) -> str: 79 return self.func( 80 f"DATE_{kind}", 81 expression.this, 82 exp.Interval(this=expression.expression, unit=unit_to_var(expression)), 83 ) 84 85 return func
110class MySQLGenerator(generator.Generator): 111 SELECT_KINDS: tuple[str, ...] = () 112 TRY_SUPPORTED = False 113 SUPPORTS_UESCAPE = False 114 SUPPORTS_DECODE_CASE = False 115 SUPPORTS_MODIFY_COLUMN = True 116 SUPPORTS_CHANGE_COLUMN = True 117 118 AFTER_HAVING_MODIFIER_TRANSFORMS = generator.AFTER_HAVING_MODIFIER_TRANSFORMS 119 120 INTERVAL_ALLOWS_PLURAL_FORM = False 121 LOCKING_READS_SUPPORTED = True 122 NULL_ORDERING_SUPPORTED: bool | None = None 123 JOIN_HINTS = False 124 TABLE_HINTS = True 125 DUPLICATE_KEY_UPDATE_WITH_SET = False 126 QUERY_HINT_SEP = " " 127 VALUES_AS_TABLE = False 128 NVL2_SUPPORTED = False 129 LAST_DAY_SUPPORTS_DATE_PART = False 130 JSON_TYPE_REQUIRED_FOR_EXTRACTION = True 131 JSON_PATH_BRACKETED_KEY_SUPPORTED = False 132 JSON_KEY_VALUE_PAIR_SEP = "," 133 SUPPORTS_TO_NUMBER = False 134 PARSE_JSON_NAME: str | None = None 135 PAD_FILL_PATTERN_IS_REQUIRED = True 136 WRAP_DERIVED_VALUES = False 137 VARCHAR_REQUIRES_SIZE = True 138 SUPPORTS_MEDIAN = False 139 UPDATE_STATEMENT_SUPPORTS_FROM = False 140 141 TRANSFORMS = { 142 **generator.Generator.TRANSFORMS, 143 exp.ArrayAgg: rename_func("GROUP_CONCAT"), 144 exp.BitwiseAndAgg: rename_func("BIT_AND"), 145 exp.BitwiseOrAgg: rename_func("BIT_OR"), 146 exp.BitwiseXorAgg: rename_func("BIT_XOR"), 147 exp.BitwiseCount: rename_func("BIT_COUNT"), 148 exp.Chr: lambda self, e: self.chr_sql(e, "CHAR"), 149 exp.CurrentDate: no_paren_current_date_sql, 150 exp.CurrentVersion: rename_func("VERSION"), 151 exp.DateDiff: _remove_ts_or_ds_to_date( 152 lambda self, e: self.func("DATEDIFF", e.this, e.expression), ("this", "expression") 153 ), 154 exp.DateAdd: _remove_ts_or_ds_to_date(date_add_sql("ADD")), 155 exp.DateStrToDate: datestrtodate_sql, 156 exp.DateSub: _remove_ts_or_ds_to_date(date_add_sql("SUB")), 157 exp.DateTrunc: _date_trunc_sql, 158 exp.Day: _remove_ts_or_ds_to_date(), 159 exp.DayOfMonth: _remove_ts_or_ds_to_date(rename_func("DAYOFMONTH")), 160 exp.DayOfWeek: _remove_ts_or_ds_to_date(rename_func("DAYOFWEEK")), 161 exp.DayOfYear: _remove_ts_or_ds_to_date(rename_func("DAYOFYEAR")), 162 exp.GroupConcat: lambda self, e: ( 163 f"""GROUP_CONCAT({self.sql(e, "this")} SEPARATOR {self.sql(e, "separator") or "','"})""" 164 ), 165 exp.ILike: no_ilike_sql, 166 exp.JSONExtractScalar: arrow_json_extract_sql, 167 exp.Length: length_or_char_length_sql, 168 exp.LogicalOr: rename_func("MAX"), 169 exp.LogicalAnd: rename_func("MIN"), 170 exp.Max: max_or_greatest, 171 exp.Min: min_or_least, 172 exp.Month: _remove_ts_or_ds_to_date(), 173 exp.NullSafeEQ: lambda self, e: self.binary(e, "<=>"), 174 exp.NullSafeNEQ: lambda self, e: f"NOT {self.binary(e, '<=>')}", 175 exp.NumberToStr: rename_func("FORMAT"), 176 exp.Pivot: no_pivot_sql, 177 exp.Select: transforms.preprocess( 178 [ 179 transforms.eliminate_distinct_on, 180 transforms.eliminate_semi_and_anti_joins, 181 transforms.eliminate_qualify, 182 transforms.eliminate_full_outer_join, 183 transforms.unnest_generate_date_array_using_recursive_cte, 184 ] 185 ), 186 exp.StrPosition: lambda self, e: strposition_sql( 187 self, e, func_name="LOCATE", supports_position=True 188 ), 189 exp.StrToDate: _str_to_date_sql, 190 exp.StrToTime: _str_to_date_sql, 191 exp.Stuff: rename_func("INSERT"), 192 exp.SessionUser: lambda *_: "SESSION_USER()", 193 exp.TableSample: no_tablesample_sql, 194 exp.TimeFromParts: rename_func("MAKETIME"), 195 exp.TimestampAdd: date_add_interval_sql("DATE", "ADD"), 196 exp.TimestampDiff: lambda self, e: self.func( 197 "TIMESTAMPDIFF", unit_to_var(e), e.expression, e.this 198 ), 199 exp.TimestampSub: date_add_interval_sql("DATE", "SUB"), 200 exp.TimeStrToUnix: rename_func("UNIX_TIMESTAMP"), 201 exp.TimeStrToTime: lambda self, e: timestrtotime_sql( 202 self, 203 e, 204 include_precision=not e.args.get("zone"), 205 ), 206 exp.TimeToStr: _remove_ts_or_ds_to_date( 207 lambda self, e: self.func("DATE_FORMAT", e.this, self.format_time(e)) 208 ), 209 exp.Trim: trim_sql, 210 exp.Trunc: rename_func("TRUNCATE"), 211 exp.TryCast: no_trycast_sql, 212 exp.TsOrDsAdd: date_add_sql("ADD"), 213 exp.TsOrDsDiff: lambda self, e: self.func("DATEDIFF", e.this, e.expression), 214 exp.TsOrDsToDate: _ts_or_ds_to_date_sql, 215 exp.Unicode: lambda self, e: f"ORD(CONVERT({self.sql(e.this)} USING utf32))", 216 exp.UnixToTime: _unix_to_time_sql, 217 exp.Week: _remove_ts_or_ds_to_date(), 218 exp.WeekOfYear: _remove_ts_or_ds_to_date(rename_func("WEEKOFYEAR")), 219 exp.Year: _remove_ts_or_ds_to_date(), 220 exp.UtcTimestamp: rename_func("UTC_TIMESTAMP"), 221 exp.UtcTime: rename_func("UTC_TIME"), 222 } 223 224 UNSIGNED_TYPE_MAPPING = { 225 exp.DType.UBIGINT: "BIGINT", 226 exp.DType.UINT: "INT", 227 exp.DType.UMEDIUMINT: "MEDIUMINT", 228 exp.DType.USMALLINT: "SMALLINT", 229 exp.DType.UTINYINT: "TINYINT", 230 exp.DType.UDECIMAL: "DECIMAL", 231 exp.DType.UDOUBLE: "DOUBLE", 232 } 233 234 TIMESTAMP_TYPE_MAPPING = { 235 exp.DType.DATETIME2: "DATETIME", 236 exp.DType.SMALLDATETIME: "DATETIME", 237 exp.DType.TIMESTAMP: "DATETIME", 238 exp.DType.TIMESTAMPNTZ: "DATETIME", 239 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 240 exp.DType.TIMESTAMPLTZ: "TIMESTAMP", 241 } 242 243 TYPE_MAPPING: t.ClassVar = { 244 exp.DType.NCHAR: "CHAR", 245 exp.DType.NVARCHAR: "VARCHAR", 246 exp.DType.INET: "INET", 247 exp.DType.ROWVERSION: "VARBINARY", 248 exp.DType.UBIGINT: "BIGINT", 249 exp.DType.UINT: "INT", 250 exp.DType.UMEDIUMINT: "MEDIUMINT", 251 exp.DType.USMALLINT: "SMALLINT", 252 exp.DType.UTINYINT: "TINYINT", 253 exp.DType.UDECIMAL: "DECIMAL", 254 exp.DType.UDOUBLE: "DOUBLE", 255 exp.DType.DATETIME2: "DATETIME", 256 exp.DType.SMALLDATETIME: "DATETIME", 257 exp.DType.TIMESTAMP: "DATETIME", 258 exp.DType.TIMESTAMPNTZ: "DATETIME", 259 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 260 exp.DType.TIMESTAMPLTZ: "TIMESTAMP", 261 } 262 263 PROPERTIES_LOCATION: t.ClassVar = { 264 **generator.Generator.PROPERTIES_LOCATION, 265 exp.TransientProperty: exp.Properties.Location.UNSUPPORTED, 266 exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED, 267 exp.PartitionedByProperty: exp.Properties.Location.UNSUPPORTED, 268 exp.PartitionByRangeProperty: exp.Properties.Location.POST_SCHEMA, 269 exp.PartitionByListProperty: exp.Properties.Location.POST_SCHEMA, 270 } 271 272 LIMIT_FETCH = "LIMIT" 273 274 LIMIT_ONLY_LITERALS = True 275 276 CHAR_CAST_MAPPING: t.ClassVar = dict.fromkeys( 277 ( 278 exp.DType.LONGTEXT, 279 exp.DType.LONGBLOB, 280 exp.DType.MEDIUMBLOB, 281 exp.DType.MEDIUMTEXT, 282 exp.DType.TEXT, 283 exp.DType.TINYBLOB, 284 exp.DType.TINYTEXT, 285 exp.DType.VARCHAR, 286 ), 287 "CHAR", 288 ) 289 SIGNED_CAST_MAPPING: t.ClassVar = dict.fromkeys( 290 ( 291 exp.DType.BIGINT, 292 exp.DType.BOOLEAN, 293 exp.DType.INT, 294 exp.DType.SMALLINT, 295 exp.DType.TINYINT, 296 exp.DType.MEDIUMINT, 297 ), 298 "SIGNED", 299 ) 300 301 # MySQL doesn't support many datatypes in cast. 302 # https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html#function_cast 303 CAST_MAPPING = { 304 exp.DType.LONGTEXT: "CHAR", 305 exp.DType.LONGBLOB: "CHAR", 306 exp.DType.MEDIUMBLOB: "CHAR", 307 exp.DType.MEDIUMTEXT: "CHAR", 308 exp.DType.TEXT: "CHAR", 309 exp.DType.TINYBLOB: "CHAR", 310 exp.DType.TINYTEXT: "CHAR", 311 exp.DType.VARCHAR: "CHAR", 312 exp.DType.BIGINT: "SIGNED", 313 exp.DType.BOOLEAN: "SIGNED", 314 exp.DType.INT: "SIGNED", 315 exp.DType.SMALLINT: "SIGNED", 316 exp.DType.TINYINT: "SIGNED", 317 exp.DType.MEDIUMINT: "SIGNED", 318 exp.DType.UBIGINT: "UNSIGNED", 319 } 320 321 TIMESTAMP_FUNC_TYPES = { 322 exp.DType.TIMESTAMPTZ, 323 exp.DType.TIMESTAMPLTZ, 324 } 325 326 # https://dev.mysql.com/doc/refman/8.0/en/keywords.html 327 RESERVED_KEYWORDS = { 328 "accessible", 329 "add", 330 "all", 331 "alter", 332 "analyze", 333 "and", 334 "as", 335 "asc", 336 "asensitive", 337 "before", 338 "between", 339 "bigint", 340 "binary", 341 "blob", 342 "both", 343 "by", 344 "call", 345 "cascade", 346 "case", 347 "change", 348 "char", 349 "character", 350 "check", 351 "collate", 352 "column", 353 "condition", 354 "constraint", 355 "continue", 356 "convert", 357 "create", 358 "cross", 359 "cube", 360 "cume_dist", 361 "current_date", 362 "current_time", 363 "current_timestamp", 364 "current_user", 365 "cursor", 366 "database", 367 "databases", 368 "day_hour", 369 "day_microsecond", 370 "day_minute", 371 "day_second", 372 "dec", 373 "decimal", 374 "declare", 375 "default", 376 "delayed", 377 "delete", 378 "dense_rank", 379 "desc", 380 "describe", 381 "deterministic", 382 "distinct", 383 "distinctrow", 384 "div", 385 "double", 386 "drop", 387 "dual", 388 "each", 389 "else", 390 "elseif", 391 "empty", 392 "enclosed", 393 "escaped", 394 "except", 395 "exists", 396 "exit", 397 "explain", 398 "false", 399 "fetch", 400 "first_value", 401 "float", 402 "float4", 403 "float8", 404 "for", 405 "force", 406 "foreign", 407 "from", 408 "fulltext", 409 "function", 410 "generated", 411 "get", 412 "grant", 413 "group", 414 "grouping", 415 "groups", 416 "having", 417 "high_priority", 418 "hour_microsecond", 419 "hour_minute", 420 "hour_second", 421 "if", 422 "ignore", 423 "in", 424 "index", 425 "infile", 426 "inner", 427 "inout", 428 "insensitive", 429 "insert", 430 "int", 431 "int1", 432 "int2", 433 "int3", 434 "int4", 435 "int8", 436 "integer", 437 "intersect", 438 "interval", 439 "into", 440 "io_after_gtids", 441 "io_before_gtids", 442 "is", 443 "iterate", 444 "join", 445 "json_table", 446 "key", 447 "keys", 448 "kill", 449 "lag", 450 "last_value", 451 "lateral", 452 "lead", 453 "leading", 454 "leave", 455 "left", 456 "like", 457 "limit", 458 "linear", 459 "lines", 460 "load", 461 "localtime", 462 "localtimestamp", 463 "lock", 464 "long", 465 "longblob", 466 "longtext", 467 "loop", 468 "low_priority", 469 "master_bind", 470 "master_ssl_verify_server_cert", 471 "match", 472 "maxvalue", 473 "mediumblob", 474 "mediumint", 475 "mediumtext", 476 "middleint", 477 "minute_microsecond", 478 "minute_second", 479 "mod", 480 "modifies", 481 "natural", 482 "not", 483 "no_write_to_binlog", 484 "nth_value", 485 "ntile", 486 "null", 487 "numeric", 488 "of", 489 "on", 490 "optimize", 491 "optimizer_costs", 492 "option", 493 "optionally", 494 "or", 495 "order", 496 "out", 497 "outer", 498 "outfile", 499 "over", 500 "partition", 501 "percent_rank", 502 "precision", 503 "primary", 504 "procedure", 505 "purge", 506 "range", 507 "rank", 508 "read", 509 "reads", 510 "read_write", 511 "real", 512 "recursive", 513 "references", 514 "regexp", 515 "release", 516 "rename", 517 "repeat", 518 "replace", 519 "require", 520 "resignal", 521 "restrict", 522 "return", 523 "revoke", 524 "right", 525 "rlike", 526 "row", 527 "rows", 528 "row_number", 529 "schema", 530 "schemas", 531 "second_microsecond", 532 "select", 533 "sensitive", 534 "separator", 535 "set", 536 "show", 537 "signal", 538 "smallint", 539 "spatial", 540 "specific", 541 "sql", 542 "sqlexception", 543 "sqlstate", 544 "sqlwarning", 545 "sql_big_result", 546 "sql_calc_found_rows", 547 "sql_small_result", 548 "ssl", 549 "starting", 550 "stored", 551 "straight_join", 552 "system", 553 "table", 554 "terminated", 555 "then", 556 "tinyblob", 557 "tinyint", 558 "tinytext", 559 "to", 560 "trailing", 561 "trigger", 562 "true", 563 "undo", 564 "union", 565 "unique", 566 "unlock", 567 "unsigned", 568 "update", 569 "usage", 570 "use", 571 "using", 572 "utc_date", 573 "utc_time", 574 "utc_timestamp", 575 "values", 576 "varbinary", 577 "varchar", 578 "varcharacter", 579 "varying", 580 "virtual", 581 "when", 582 "where", 583 "while", 584 "window", 585 "with", 586 "write", 587 "xor", 588 "year_month", 589 "zerofill", 590 } 591 592 SQL_SECURITY_VIEW_LOCATION = exp.Properties.Location.POST_CREATE 593 594 def locate_properties(self, properties: exp.Properties) -> defaultdict: 595 locations = super().locate_properties(properties) 596 597 # MySQL puts SQL SECURITY before VIEW but after the schema for functions/procedures 598 if isinstance(create := properties.parent, exp.Create) and create.kind == "VIEW": 599 post_schema = locations[exp.Properties.Location.POST_SCHEMA] 600 for i, p in enumerate(post_schema): 601 if isinstance(p, exp.SqlSecurityProperty): 602 post_schema.pop(i) 603 locations[self.SQL_SECURITY_VIEW_LOCATION].append(p) 604 break 605 606 return locations 607 608 def computedcolumnconstraint_sql(self, expression: exp.ComputedColumnConstraint) -> str: 609 persisted = "STORED" if expression.args.get("persisted") else "VIRTUAL" 610 return f"GENERATED ALWAYS AS ({self.sql(expression.this.unnest())}) {persisted}" 611 612 def array_sql(self, expression: exp.Array) -> str: 613 self.unsupported("Arrays are not supported by MySQL") 614 return self.function_fallback_sql(expression) 615 616 def arraycontainsall_sql(self, expression: exp.ArrayContainsAll) -> str: 617 self.unsupported("Array operations are not supported by MySQL") 618 return self.function_fallback_sql(expression) 619 620 def dpipe_sql(self, expression: exp.DPipe) -> str: 621 return self.func("CONCAT", *expression.flatten()) 622 623 def extract_sql(self, expression: exp.Extract) -> str: 624 unit = expression.name 625 if unit and unit.lower() == "epoch": 626 return self.func("UNIX_TIMESTAMP", expression.expression) 627 628 return super().extract_sql(expression) 629 630 def datatype_sql(self, expression: exp.DataType) -> str: 631 if ( 632 self.VARCHAR_REQUIRES_SIZE 633 and expression.is_type(exp.DType.VARCHAR) 634 and not expression.expressions 635 ): 636 # `VARCHAR` must always have a size - if it doesn't, we always generate `TEXT` 637 return "TEXT" 638 639 # https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html 640 result = super().datatype_sql(expression) 641 if expression.this in self.UNSIGNED_TYPE_MAPPING: 642 result = f"{result} UNSIGNED" 643 644 return result 645 646 def jsonarraycontains_sql(self, expression: exp.JSONArrayContains) -> str: 647 return f"{self.sql(expression, 'this')} MEMBER OF({self.sql(expression, 'expression')})" 648 649 def cast_sql(self, expression: exp.Cast, safe_prefix: str | None = None) -> str: 650 if expression.to.this in self.TIMESTAMP_FUNC_TYPES: 651 return self.func("TIMESTAMP", expression.this) 652 653 to = self.CAST_MAPPING.get(expression.to.this) 654 655 if to: 656 expression.to.set("this", to) 657 return super().cast_sql(expression) 658 659 def show_sql(self, expression: exp.Show) -> str: 660 this = f" {expression.name}" 661 full = " FULL" if expression.args.get("full") else "" 662 global_ = " GLOBAL" if expression.args.get("global_") else "" 663 664 target = self.sql(expression, "target") 665 target = f" {target}" if target else "" 666 if expression.name in ("COLUMNS", "INDEX"): 667 target = f" FROM{target}" 668 elif expression.name == "GRANTS": 669 target = f" FOR{target}" 670 elif expression.name in ("LINKS", "PARTITIONS"): 671 target = f" ON{target}" if target else "" 672 elif expression.name == "PROJECTIONS": 673 target = f" ON TABLE{target}" if target else "" 674 675 db = self._prefixed_sql("FROM", expression, "db") 676 677 like = self._prefixed_sql("LIKE", expression, "like") 678 where = self.sql(expression, "where") 679 680 types = self.expressions(expression, key="types") 681 types = f" {types}" if types else types 682 query = self._prefixed_sql("FOR QUERY", expression, "query") 683 684 if expression.name == "PROFILE": 685 offset = self._prefixed_sql("OFFSET", expression, "offset") 686 limit = self._prefixed_sql("LIMIT", expression, "limit") 687 else: 688 offset = "" 689 limit = self._oldstyle_limit_sql(expression) 690 691 log = self._prefixed_sql("IN", expression, "log") 692 position = self._prefixed_sql("FROM", expression, "position") 693 694 channel = self._prefixed_sql("FOR CHANNEL", expression, "channel") 695 696 if expression.name == "ENGINE": 697 mutex_or_status = " MUTEX" if expression.args.get("mutex") else " STATUS" 698 else: 699 mutex_or_status = "" 700 701 for_table = self._prefixed_sql("FOR TABLE", expression, "for_table") 702 for_group = self._prefixed_sql("FOR GROUP", expression, "for_group") 703 for_user = self._prefixed_sql("FOR USER", expression, "for_user") 704 for_role = self._prefixed_sql("FOR ROLE", expression, "for_role") 705 into_outfile = self._prefixed_sql("INTO OUTFILE", expression, "into_outfile") 706 json = " JSON" if expression.args.get("json") else "" 707 708 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}" 709 710 def alterrename_sql(self, expression: exp.AlterRename, include_to: bool = True) -> str: 711 """To avoid TO keyword in ALTER ... RENAME statements. 712 It's moved from Doris, because it's the same for all MySQL, Doris, and StarRocks. 713 """ 714 return super().alterrename_sql(expression, include_to=False) 715 716 def altercolumn_sql(self, expression: exp.AlterColumn) -> str: 717 dtype = self.sql(expression, "dtype") 718 if not dtype: 719 return super().altercolumn_sql(expression) 720 721 this = self.sql(expression, "this") 722 return f"MODIFY COLUMN {this} {dtype}" 723 724 def _prefixed_sql(self, prefix: str, expression: exp.Expr, arg: str) -> str: 725 sql = self.sql(expression, arg) 726 return f" {prefix} {sql}" if sql else "" 727 728 def _oldstyle_limit_sql(self, expression: exp.Show) -> str: 729 limit = self.sql(expression, "limit") 730 offset = self.sql(expression, "offset") 731 if limit: 732 limit_offset = f"{offset}, {limit}" if offset else limit 733 return f" LIMIT {limit_offset}" 734 return "" 735 736 def timestamptrunc_sql(self, expression: exp.TimestampTrunc) -> str: 737 unit = expression.args.get("unit") 738 739 # Pick an old-enough date to avoid negative timestamp diffs 740 start_ts = "'0000-01-01 00:00:00'" 741 742 # Source: https://stackoverflow.com/a/32955740 743 timestamp_diff = build_date_delta(exp.TimestampDiff)([unit, start_ts, expression.this]) 744 interval = exp.Interval(this=timestamp_diff, unit=unit) 745 dateadd = build_date_delta_with_interval(exp.DateAdd)([start_ts, interval]) 746 747 return self.sql(dateadd) 748 749 def converttimezone_sql(self, expression: exp.ConvertTimezone) -> str: 750 from_tz = expression.args.get("source_tz") 751 to_tz = expression.args.get("target_tz") 752 dt = expression.args.get("timestamp") 753 754 return self.func("CONVERT_TZ", dt, from_tz, to_tz) 755 756 def attimezone_sql(self, expression: exp.AtTimeZone) -> str: 757 self.unsupported("AT TIME ZONE is not supported by MySQL") 758 return self.sql(expression.this) 759 760 def isascii_sql(self, expression: exp.IsAscii) -> str: 761 return f"REGEXP_LIKE({self.sql(expression.this)}, '^[[:ascii:]]*$')" 762 763 def ignorenulls_sql(self, expression: exp.IgnoreNulls) -> str: 764 # https://dev.mysql.com/doc/refman/8.4/en/window-function-descriptions.html 765 self.unsupported("MySQL does not support IGNORE NULLS.") 766 return self.sql(expression.this) 767 768 @unsupported_args("this") 769 def currentschema_sql(self, expression: exp.CurrentSchema) -> str: 770 return self.func("SCHEMA") 771 772 def partition_sql(self, expression: exp.Partition) -> str: 773 parent = expression.parent 774 if isinstance(parent, (exp.PartitionByRangeProperty, exp.PartitionByListProperty)): 775 return self.expressions(expression, flat=True) 776 return super().partition_sql(expression) 777 778 def _partition_by_sql( 779 self, expression: exp.PartitionByRangeProperty | exp.PartitionByListProperty, kind: str 780 ) -> str: 781 partitions = self.expressions(expression, key="partition_expressions", flat=True) 782 create = self.expressions(expression, key="create_expressions", flat=True) 783 return f"PARTITION BY {kind} ({partitions}) ({create})" 784 785 def partitionbyrangeproperty_sql(self, expression: exp.PartitionByRangeProperty) -> str: 786 return self._partition_by_sql(expression, "RANGE") 787 788 def partitionbylistproperty_sql(self, expression: exp.PartitionByListProperty) -> str: 789 return self._partition_by_sql(expression, "LIST") 790 791 def partitionlist_sql(self, expression: exp.PartitionList) -> str: 792 name = self.sql(expression, "this") 793 values = self.expressions(expression, flat=True) 794 return f"PARTITION {name} VALUES IN ({values})" 795 796 def partitionrange_sql(self, expression: exp.PartitionRange) -> str: 797 name = self.sql(expression, "this") 798 values = self.expressions(expression, flat=True) 799 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
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.ArrayContainsAll'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.ArrayOverlaps'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.AssumeColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.AutoRefreshProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.BackupProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CaseSpecificColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.math.Ceil'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CharacterSetColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CharacterSetProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.ClusteredColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CollateColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CommentColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.ConnectByRoot'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.string.ConvertToCharset'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CopyGrantsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CredentialsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.CurrentCatalog'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.SessionUser'>: <function 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.JSONBDeleteAtPath'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONObject'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONObjectAgg'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.LanguageProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.LocationProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.LogProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.MaskingProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.MaterializedProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.NetFunc'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.NetworkProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.NonClusteredColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.NoPrimaryIndexProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.NotForReplicationColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.OnCommitProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.OnProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.OnUpdateColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.Operator'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.OutputModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.ExtendsLeft'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.ExtendsRight'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.PathColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.PartitionedByBucket'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.PartitionByTruncate'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.PivotAny'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.PositionalColumn'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.ProjectionPolicyColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.InvisibleColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.ZeroFillColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Put'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.RemoteWithConnectionModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ReturnsProperty'>: <function 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 _remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.temporal.DateStrToDate'>: <function datestrtodate_sql>, <class 'sqlglot.expressions.temporal.DateSub'>: <function _remove_ts_or_ds_to_date.<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.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.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 rename_func.<locals>.<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.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 =
{<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 =
{<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.AllowedValuesProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.AlgorithmProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.ApiProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.ApplicationProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.AutoIncrementProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.AutoRefreshProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.BackupProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.BlockCompressionProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.CatalogProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.CharacterSetProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ChecksumProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.CollateProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ComputeProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.CopyGrantsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.query.Cluster'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ClusteredByProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DistributedByProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DuplicateKeyProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DataBlocksizeProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.DatabaseProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.DataDeletionProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DefinerProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.DictRange'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DictProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DynamicProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.DistKeyProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DistStyleProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.EmptyProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.EncodeProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.EngineProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.EnviromentProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.HandlerProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ParameterStyleProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ExecuteAsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ExternalProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.FallbackProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.FileFormatProperty'>: <PropertiesLocation.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.properties.FreespaceProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.GlobalProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.HeapProperty'>: <PropertiesLocation.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.properties.HybridProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.InheritsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.IcebergProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.IncludeProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.InputModelProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.IsolatedLoadingProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.JournalProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.LanguageProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.LikeProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.LocationProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.LockProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.LockingProperty'>: <PropertiesLocation.POST_ALIAS: 'POST_ALIAS'>, <class 'sqlglot.expressions.properties.LogProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.MaskingProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.MaterializedProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.MergeBlockRatioProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.ModuleProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.NetworkProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.NoPrimaryIndexProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.OnProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.OnCommitProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.query.Order'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.OutputModelProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.PartitionedByProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.PartitionedOfProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.constraints.PrimaryKey'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.Property'>: <PropertiesLocation.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.properties.RefreshTriggerProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.RemoteWithConnectionModelProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ReturnsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.RollupProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.RowAccessProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.RowFormatProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.RowFormatDelimitedProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.RowFormatSerdeProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SampleProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SchemaCommentProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SecureProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.SecurityIntegrationProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.SerdeProperties'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.ddl.Set'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SettingsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SetProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.SetConfigProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SharingProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.ddl.SequenceProperties'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.ddl.TriggerProperties'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.SortKeyProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SqlReadWriteProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SqlSecurityProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.StabilityProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.StorageHandlerProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.StreamingTableProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.StrictProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.Tags'>: <PropertiesLocation.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.properties.TemporaryProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.ToTableProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.TransientProperty'>: <PropertiesLocation.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 =
{<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'}
RESERVED_KEYWORDS =
{'iterate', 'json_table', 'grouping', 'limit', 'join', 'maxvalue', 'get', 'modifies', 'signal', 'create', 'of', 'asc', 'as', 'no_write_to_binlog', 'distinctrow', 'localtimestamp', 'having', 'virtual', 'left', 'escaped', 'real', 'each', 'double', 'read', 'tinyblob', 'exists', 'optionally', 'varchar', 'usage', 'false', 'into', 'write', 'load', 'current_user', 'enclosed', 'accessible', 'numeric', 'system', 'inout', 'utc_timestamp', 'default', 'specific', 'constraint', 'infile', 'day_microsecond', 'row_number', 'int8', 'both', 'rlike', 'leading', 'precision', 'window', 'update', 'current_date', 'order', 'second_microsecond', 'character', 'primary', 'kill', 'dual', 'empty', 'minute_microsecond', 'nth_value', 'mediumtext', 'sql_big_result', 'asensitive', 'return', 'using', 'hour_second', 'select', 'right', 'groups', 'div', 'all', 'cross', 'tinytext', 'exit', 'regexp', 'cursor', 'true', 'binary', 'collate', 'elseif', 'by', 'between', 'varcharacter', 'current_timestamp', 'key', 'stored', 'alter', 'or', 'column', 'decimal', 'drop', 'release', 'int3', 'bigint', 'utc_date', 'set', 'sql', 'mediumint', 'trailing', 'spatial', 'values', 'lines', 'sensitive', 'optimizer_costs', 'dec', 'current_time', 'deterministic', 'unique', 'starting', 'delete', 'index', 'if', 'varying', 'inner', 'io_after_gtids', 'not', 'insensitive', 'show', 'day_minute', 'sql_calc_found_rows', 'master_ssl_verify_server_cert', 'schemas', 'percent_rank', 'in', 'int1', 'case', 'minute_second', 'high_priority', 'io_before_gtids', 'unlock', 'unsigned', 'loop', 'float8', 'lead', 'zerofill', 'cascade', 'mediumblob', 'foreign', 'add', 'day_second', 'optimize', 'partition', 'desc', 'describe', 'lock', 'sqlwarning', 'insert', 'int2', 'rename', 'match', 'declare', 'interval', 'convert', 'fetch', 'restrict', 'out', 'ignore', 'sqlexception', 'sqlstate', 'longtext', 'analyze', 'then', 'master_bind', 'mod', 'to', 'union', 'before', 'day_hour', 'change', 'repeat', 'separator', 'is', 'revoke', 'last_value', 'option', 'rows', 'fulltext', 'range', 'trigger', 'longblob', 'dense_rank', 'middleint', 'undo', 'leave', 'check', 'terminated', 'lateral', 'linear', 'schema', 'float4', 'delayed', 'cube', 'require', 'like', 'table', 'row', 'int', 'natural', 'with', 'rank', 'lag', 'low_priority', 'group', 'blob', 'references', 'float', 'hour_minute', 'procedure', 'localtime', 'sql_small_result', 'year_month', 'outfile', 'varbinary', 'outer', 'tinyint', 'except', 'generated', 'replace', 'reads', 'else', 'while', 'smallint', 'null', 'distinct', 'grant', 'integer', 'where', 'int4', 'from', 'explain', 'continue', 'keys', 'use', 'cume_dist', 'recursive', 'hour_microsecond', 'read_write', 'purge', 'first_value', 'condition', 'intersect', 'straight_join', 'on', 'over', 'database', 'ssl', 'utc_time', 'call', 'databases', 'function', 'when', 'for', 'xor', 'resignal', 'long', 'char', 'force', 'and', 'ntile'}
def
locate_properties( self, properties: sqlglot.expressions.properties.Properties) -> collections.defaultdict:
594 def locate_properties(self, properties: exp.Properties) -> defaultdict: 595 locations = super().locate_properties(properties) 596 597 # MySQL puts SQL SECURITY before VIEW but after the schema for functions/procedures 598 if isinstance(create := properties.parent, exp.Create) and create.kind == "VIEW": 599 post_schema = locations[exp.Properties.Location.POST_SCHEMA] 600 for i, p in enumerate(post_schema): 601 if isinstance(p, exp.SqlSecurityProperty): 602 post_schema.pop(i) 603 locations[self.SQL_SECURITY_VIEW_LOCATION].append(p) 604 break 605 606 return locations
def
computedcolumnconstraint_sql( self, expression: sqlglot.expressions.constraints.ComputedColumnConstraint) -> str:
630 def datatype_sql(self, expression: exp.DataType) -> str: 631 if ( 632 self.VARCHAR_REQUIRES_SIZE 633 and expression.is_type(exp.DType.VARCHAR) 634 and not expression.expressions 635 ): 636 # `VARCHAR` must always have a size - if it doesn't, we always generate `TEXT` 637 return "TEXT" 638 639 # https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html 640 result = super().datatype_sql(expression) 641 if expression.this in self.UNSIGNED_TYPE_MAPPING: 642 result = f"{result} UNSIGNED" 643 644 return result
def
cast_sql( self, expression: sqlglot.expressions.functions.Cast, safe_prefix: str | None = None) -> str:
649 def cast_sql(self, expression: exp.Cast, safe_prefix: str | None = None) -> str: 650 if expression.to.this in self.TIMESTAMP_FUNC_TYPES: 651 return self.func("TIMESTAMP", expression.this) 652 653 to = self.CAST_MAPPING.get(expression.to.this) 654 655 if to: 656 expression.to.set("this", to) 657 return super().cast_sql(expression)
659 def show_sql(self, expression: exp.Show) -> str: 660 this = f" {expression.name}" 661 full = " FULL" if expression.args.get("full") else "" 662 global_ = " GLOBAL" if expression.args.get("global_") else "" 663 664 target = self.sql(expression, "target") 665 target = f" {target}" if target else "" 666 if expression.name in ("COLUMNS", "INDEX"): 667 target = f" FROM{target}" 668 elif expression.name == "GRANTS": 669 target = f" FOR{target}" 670 elif expression.name in ("LINKS", "PARTITIONS"): 671 target = f" ON{target}" if target else "" 672 elif expression.name == "PROJECTIONS": 673 target = f" ON TABLE{target}" if target else "" 674 675 db = self._prefixed_sql("FROM", expression, "db") 676 677 like = self._prefixed_sql("LIKE", expression, "like") 678 where = self.sql(expression, "where") 679 680 types = self.expressions(expression, key="types") 681 types = f" {types}" if types else types 682 query = self._prefixed_sql("FOR QUERY", expression, "query") 683 684 if expression.name == "PROFILE": 685 offset = self._prefixed_sql("OFFSET", expression, "offset") 686 limit = self._prefixed_sql("LIMIT", expression, "limit") 687 else: 688 offset = "" 689 limit = self._oldstyle_limit_sql(expression) 690 691 log = self._prefixed_sql("IN", expression, "log") 692 position = self._prefixed_sql("FROM", expression, "position") 693 694 channel = self._prefixed_sql("FOR CHANNEL", expression, "channel") 695 696 if expression.name == "ENGINE": 697 mutex_or_status = " MUTEX" if expression.args.get("mutex") else " STATUS" 698 else: 699 mutex_or_status = "" 700 701 for_table = self._prefixed_sql("FOR TABLE", expression, "for_table") 702 for_group = self._prefixed_sql("FOR GROUP", expression, "for_group") 703 for_user = self._prefixed_sql("FOR USER", expression, "for_user") 704 for_role = self._prefixed_sql("FOR ROLE", expression, "for_role") 705 into_outfile = self._prefixed_sql("INTO OUTFILE", expression, "into_outfile") 706 json = " JSON" if expression.args.get("json") else "" 707 708 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:
710 def alterrename_sql(self, expression: exp.AlterRename, include_to: bool = True) -> str: 711 """To avoid TO keyword in ALTER ... RENAME statements. 712 It's moved from Doris, because it's the same for all MySQL, Doris, and StarRocks. 713 """ 714 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.
736 def timestamptrunc_sql(self, expression: exp.TimestampTrunc) -> str: 737 unit = expression.args.get("unit") 738 739 # Pick an old-enough date to avoid negative timestamp diffs 740 start_ts = "'0000-01-01 00:00:00'" 741 742 # Source: https://stackoverflow.com/a/32955740 743 timestamp_diff = build_date_delta(exp.TimestampDiff)([unit, start_ts, expression.this]) 744 interval = exp.Interval(this=timestamp_diff, unit=unit) 745 dateadd = build_date_delta_with_interval(exp.DateAdd)([start_ts, interval]) 746 747 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
- RENAME_TABLE_WITH_DB
- GROUPINGS_SEP
- INDEX_ON
- INOUT_SEPARATOR
- DIRECTED_JOINS
- QUERY_HINTS
- IS_BOOL_ALLOWED
- LIMIT_IS_TOP
- RETURNING_END
- EXTRACT_ALLOWS_QUOTES
- TZ_TO_WITH_TIME_ZONE
- ALTER_TABLE_INCLUDE_COLUMN_KEYWORD
- UNNEST_WITH_ORDINALITY
- AGGREGATE_FILTER_SUPPORTED
- SEMI_ANTI_JOIN_WITH_SIDE
- COMPUTED_COLUMN_WITH_TYPE
- SUPPORTS_TABLE_COPY
- TABLESAMPLE_REQUIRES_PARENS
- TABLESAMPLE_SIZE_IS_ROWS
- TABLESAMPLE_KEYWORDS
- TABLESAMPLE_WITH_METHOD
- TABLESAMPLE_SEED_KEYWORD
- 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
- INSERT_OVERWRITE
- SUPPORTS_SELECT_INTO
- SUPPORTS_UNLOGGED_TABLES
- SUPPORTS_CREATE_TABLE_LIKE
- LIKE_PROPERTY_INSIDE_SCHEMA
- MULTI_ARG_DISTINCT
- JSON_PATH_SINGLE_QUOTE_ESCAPE
- SUPPORTED_JSON_PATH_PARTS
- CAN_IMPLEMENT_ARRAY_ANY
- SUPPORTS_WINDOW_EXCLUDE
- SET_OP_MODIFIERS
- 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
- 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
- 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
- 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
- distribute_sql
- sort_sql
- ordered_sql
- matchrecognizemeasure_sql
- matchrecognize_sql
- query_modifiers
- options_modifier
- for_modifiers
- queryoption_sql
- offset_limit_modifiers
- after_limit_modifiers
- select_sql
- schema_sql
- schema_columns_sql
- star_sql
- parameter_sql
- sessionparameter_sql
- placeholder_sql
- subquery_sql
- qualify_sql
- unnest_sql
- prewhere_sql
- where_sql
- window_sql
- partition_by_sql
- windowspec_sql
- withingroup_sql
- between_sql
- bracket_offset_expressions
- 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
- 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
- add_sql
- and_sql
- or_sql
- xor_sql
- connector_sql
- bitwiseand_sql
- bitwiseleftshift_sql
- bitwisenot_sql
- bitwiseor_sql
- bitwiserightshift_sql
- bitwisexor_sql
- strtotime_sql
- currentdate_sql
- collate_sql
- command_sql
- comment_sql
- mergetreettlaction_sql
- mergetreettl_sql
- transaction_sql
- commit_sql
- rollback_sql
- 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
- addpartition_sql
- distinct_sql
- respectnulls_sql
- havingmax_sql
- intdiv_sql
- div_sql
- safedivide_sql
- overlaps_sql
- distance_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
- func
- format_args
- too_wide
- format_time
- expressions
- op_expressions
- naked_property
- tag_sql
- token_sql
- userdefinedfunction_sql
- joinhint_sql
- kwarg_sql
- when_sql
- whens_sql
- merge_sql
- tochar_sql
- tonumber_sql
- dictproperty_sql
- dictrange_sql
- dictsubproperty_sql
- duplicatekeyproperty_sql
- uniquekeyproperty_sql
- distributedbyproperty_sql
- oncluster_sql
- clusteredbyproperty_sql
- anyvalue_sql
- querytransform_sql
- indexconstraintoption_sql
- checkcolumnconstraint_sql
- indexcolumnconstraint_sql
- nvl2_sql
- comprehension_sql
- columnprefix_sql
- opclass_sql
- predict_sql
- generateembedding_sql
- generatetext_sql
- generatetable_sql
- generatebool_sql
- generateint_sql
- generatedouble_sql
- mltranslate_sql
- mlforecast_sql
- aiforecast_sql
- featuresattime_sql
- vectorsearch_sql
- forin_sql
- refresh_sql
- toarray_sql
- tsordstotime_sql
- tsordstotimestamp_sql
- tsordstodatetime_sql
- tsordstodate_sql
- unixdate_sql
- lastday_sql
- dateadd_sql
- arrayany_sql
- struct_sql
- 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
- 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
- get_put_sql
- translatecharacters_sql
- decodecase_sql
- semanticview_sql
- getextract_sql
- datefromunixdate_sql
- space_sql
- buildproperty_sql
- refreshtriggerproperty_sql
- modelattribute_sql
- directorystage_sql
- uuid_sql
- initcap_sql
- localtime_sql
- localtimestamp_sql
- weekstart_sql
- chr_sql
- block_sql
- storedprocedure_sql
- ifblock_sql
- whileblock_sql
- execute_sql
- executesql_sql
- altermodifysqlsecurity_sql
- usingproperty_sql
- renameindex_sql