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 115 AFTER_HAVING_MODIFIER_TRANSFORMS = generator.AFTER_HAVING_MODIFIER_TRANSFORMS 116 117 INTERVAL_ALLOWS_PLURAL_FORM = False 118 LOCKING_READS_SUPPORTED = True 119 NULL_ORDERING_SUPPORTED: bool | None = None 120 JOIN_HINTS = False 121 TABLE_HINTS = True 122 DUPLICATE_KEY_UPDATE_WITH_SET = False 123 QUERY_HINT_SEP = " " 124 VALUES_AS_TABLE = False 125 NVL2_SUPPORTED = False 126 LAST_DAY_SUPPORTS_DATE_PART = False 127 JSON_TYPE_REQUIRED_FOR_EXTRACTION = True 128 JSON_PATH_BRACKETED_KEY_SUPPORTED = False 129 JSON_KEY_VALUE_PAIR_SEP = "," 130 SUPPORTS_TO_NUMBER = False 131 PARSE_JSON_NAME: str | None = None 132 PAD_FILL_PATTERN_IS_REQUIRED = True 133 WRAP_DERIVED_VALUES = False 134 VARCHAR_REQUIRES_SIZE = True 135 SUPPORTS_MEDIAN = False 136 UPDATE_STATEMENT_SUPPORTS_FROM = False 137 138 TRANSFORMS = { 139 **generator.Generator.TRANSFORMS, 140 exp.ArrayAgg: rename_func("GROUP_CONCAT"), 141 exp.BitwiseAndAgg: rename_func("BIT_AND"), 142 exp.BitwiseOrAgg: rename_func("BIT_OR"), 143 exp.BitwiseXorAgg: rename_func("BIT_XOR"), 144 exp.BitwiseCount: rename_func("BIT_COUNT"), 145 exp.Chr: lambda self, e: self.chr_sql(e, "CHAR"), 146 exp.CurrentDate: no_paren_current_date_sql, 147 exp.CurrentVersion: rename_func("VERSION"), 148 exp.DateDiff: _remove_ts_or_ds_to_date( 149 lambda self, e: self.func("DATEDIFF", e.this, e.expression), ("this", "expression") 150 ), 151 exp.DateAdd: _remove_ts_or_ds_to_date(date_add_sql("ADD")), 152 exp.DateStrToDate: datestrtodate_sql, 153 exp.DateSub: _remove_ts_or_ds_to_date(date_add_sql("SUB")), 154 exp.DateTrunc: _date_trunc_sql, 155 exp.Day: _remove_ts_or_ds_to_date(), 156 exp.DayOfMonth: _remove_ts_or_ds_to_date(rename_func("DAYOFMONTH")), 157 exp.DayOfWeek: _remove_ts_or_ds_to_date(rename_func("DAYOFWEEK")), 158 exp.DayOfYear: _remove_ts_or_ds_to_date(rename_func("DAYOFYEAR")), 159 exp.GroupConcat: lambda self, e: ( 160 f"""GROUP_CONCAT({self.sql(e, "this")} SEPARATOR {self.sql(e, "separator") or "','"})""" 161 ), 162 exp.ILike: no_ilike_sql, 163 exp.JSONExtractScalar: arrow_json_extract_sql, 164 exp.Length: length_or_char_length_sql, 165 exp.LogicalOr: rename_func("MAX"), 166 exp.LogicalAnd: rename_func("MIN"), 167 exp.Max: max_or_greatest, 168 exp.Min: min_or_least, 169 exp.Month: _remove_ts_or_ds_to_date(), 170 exp.NullSafeEQ: lambda self, e: self.binary(e, "<=>"), 171 exp.NullSafeNEQ: lambda self, e: f"NOT {self.binary(e, '<=>')}", 172 exp.NumberToStr: rename_func("FORMAT"), 173 exp.Pivot: no_pivot_sql, 174 exp.Select: transforms.preprocess( 175 [ 176 transforms.eliminate_distinct_on, 177 transforms.eliminate_semi_and_anti_joins, 178 transforms.eliminate_qualify, 179 transforms.eliminate_full_outer_join, 180 transforms.unnest_generate_date_array_using_recursive_cte, 181 ] 182 ), 183 exp.StrPosition: lambda self, e: strposition_sql( 184 self, e, func_name="LOCATE", supports_position=True 185 ), 186 exp.StrToDate: _str_to_date_sql, 187 exp.StrToTime: _str_to_date_sql, 188 exp.Stuff: rename_func("INSERT"), 189 exp.SessionUser: lambda *_: "SESSION_USER()", 190 exp.TableSample: no_tablesample_sql, 191 exp.TimeFromParts: rename_func("MAKETIME"), 192 exp.TimestampAdd: date_add_interval_sql("DATE", "ADD"), 193 exp.TimestampDiff: lambda self, e: self.func( 194 "TIMESTAMPDIFF", unit_to_var(e), e.expression, e.this 195 ), 196 exp.TimestampSub: date_add_interval_sql("DATE", "SUB"), 197 exp.TimeStrToUnix: rename_func("UNIX_TIMESTAMP"), 198 exp.TimeStrToTime: lambda self, e: timestrtotime_sql( 199 self, 200 e, 201 include_precision=not e.args.get("zone"), 202 ), 203 exp.TimeToStr: _remove_ts_or_ds_to_date( 204 lambda self, e: self.func("DATE_FORMAT", e.this, self.format_time(e)) 205 ), 206 exp.Trim: trim_sql, 207 exp.Trunc: rename_func("TRUNCATE"), 208 exp.TryCast: no_trycast_sql, 209 exp.TsOrDsAdd: date_add_sql("ADD"), 210 exp.TsOrDsDiff: lambda self, e: self.func("DATEDIFF", e.this, e.expression), 211 exp.TsOrDsToDate: _ts_or_ds_to_date_sql, 212 exp.Unicode: lambda self, e: f"ORD(CONVERT({self.sql(e.this)} USING utf32))", 213 exp.UnixToTime: _unix_to_time_sql, 214 exp.Week: _remove_ts_or_ds_to_date(), 215 exp.WeekOfYear: _remove_ts_or_ds_to_date(rename_func("WEEKOFYEAR")), 216 exp.Year: _remove_ts_or_ds_to_date(), 217 exp.UtcTimestamp: rename_func("UTC_TIMESTAMP"), 218 exp.UtcTime: rename_func("UTC_TIME"), 219 } 220 221 UNSIGNED_TYPE_MAPPING = { 222 exp.DType.UBIGINT: "BIGINT", 223 exp.DType.UINT: "INT", 224 exp.DType.UMEDIUMINT: "MEDIUMINT", 225 exp.DType.USMALLINT: "SMALLINT", 226 exp.DType.UTINYINT: "TINYINT", 227 exp.DType.UDECIMAL: "DECIMAL", 228 exp.DType.UDOUBLE: "DOUBLE", 229 } 230 231 TIMESTAMP_TYPE_MAPPING = { 232 exp.DType.DATETIME2: "DATETIME", 233 exp.DType.SMALLDATETIME: "DATETIME", 234 exp.DType.TIMESTAMP: "DATETIME", 235 exp.DType.TIMESTAMPNTZ: "DATETIME", 236 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 237 exp.DType.TIMESTAMPLTZ: "TIMESTAMP", 238 } 239 240 TYPE_MAPPING: t.ClassVar = { 241 exp.DType.NCHAR: "CHAR", 242 exp.DType.NVARCHAR: "VARCHAR", 243 exp.DType.INET: "INET", 244 exp.DType.ROWVERSION: "VARBINARY", 245 exp.DType.UBIGINT: "BIGINT", 246 exp.DType.UINT: "INT", 247 exp.DType.UMEDIUMINT: "MEDIUMINT", 248 exp.DType.USMALLINT: "SMALLINT", 249 exp.DType.UTINYINT: "TINYINT", 250 exp.DType.UDECIMAL: "DECIMAL", 251 exp.DType.UDOUBLE: "DOUBLE", 252 exp.DType.DATETIME2: "DATETIME", 253 exp.DType.SMALLDATETIME: "DATETIME", 254 exp.DType.TIMESTAMP: "DATETIME", 255 exp.DType.TIMESTAMPNTZ: "DATETIME", 256 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 257 exp.DType.TIMESTAMPLTZ: "TIMESTAMP", 258 } 259 260 PROPERTIES_LOCATION: t.ClassVar = { 261 **generator.Generator.PROPERTIES_LOCATION, 262 exp.TransientProperty: exp.Properties.Location.UNSUPPORTED, 263 exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED, 264 exp.PartitionedByProperty: exp.Properties.Location.UNSUPPORTED, 265 exp.PartitionByRangeProperty: exp.Properties.Location.POST_SCHEMA, 266 exp.PartitionByListProperty: exp.Properties.Location.POST_SCHEMA, 267 } 268 269 LIMIT_FETCH = "LIMIT" 270 271 LIMIT_ONLY_LITERALS = True 272 273 CHAR_CAST_MAPPING: t.ClassVar = dict.fromkeys( 274 ( 275 exp.DType.LONGTEXT, 276 exp.DType.LONGBLOB, 277 exp.DType.MEDIUMBLOB, 278 exp.DType.MEDIUMTEXT, 279 exp.DType.TEXT, 280 exp.DType.TINYBLOB, 281 exp.DType.TINYTEXT, 282 exp.DType.VARCHAR, 283 ), 284 "CHAR", 285 ) 286 SIGNED_CAST_MAPPING: t.ClassVar = dict.fromkeys( 287 ( 288 exp.DType.BIGINT, 289 exp.DType.BOOLEAN, 290 exp.DType.INT, 291 exp.DType.SMALLINT, 292 exp.DType.TINYINT, 293 exp.DType.MEDIUMINT, 294 ), 295 "SIGNED", 296 ) 297 298 # MySQL doesn't support many datatypes in cast. 299 # https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html#function_cast 300 CAST_MAPPING = { 301 exp.DType.LONGTEXT: "CHAR", 302 exp.DType.LONGBLOB: "CHAR", 303 exp.DType.MEDIUMBLOB: "CHAR", 304 exp.DType.MEDIUMTEXT: "CHAR", 305 exp.DType.TEXT: "CHAR", 306 exp.DType.TINYBLOB: "CHAR", 307 exp.DType.TINYTEXT: "CHAR", 308 exp.DType.VARCHAR: "CHAR", 309 exp.DType.BIGINT: "SIGNED", 310 exp.DType.BOOLEAN: "SIGNED", 311 exp.DType.INT: "SIGNED", 312 exp.DType.SMALLINT: "SIGNED", 313 exp.DType.TINYINT: "SIGNED", 314 exp.DType.MEDIUMINT: "SIGNED", 315 exp.DType.UBIGINT: "UNSIGNED", 316 } 317 318 TIMESTAMP_FUNC_TYPES = { 319 exp.DType.TIMESTAMPTZ, 320 exp.DType.TIMESTAMPLTZ, 321 } 322 323 # https://dev.mysql.com/doc/refman/8.0/en/keywords.html 324 RESERVED_KEYWORDS = { 325 "accessible", 326 "add", 327 "all", 328 "alter", 329 "analyze", 330 "and", 331 "as", 332 "asc", 333 "asensitive", 334 "before", 335 "between", 336 "bigint", 337 "binary", 338 "blob", 339 "both", 340 "by", 341 "call", 342 "cascade", 343 "case", 344 "change", 345 "char", 346 "character", 347 "check", 348 "collate", 349 "column", 350 "condition", 351 "constraint", 352 "continue", 353 "convert", 354 "create", 355 "cross", 356 "cube", 357 "cume_dist", 358 "current_date", 359 "current_time", 360 "current_timestamp", 361 "current_user", 362 "cursor", 363 "database", 364 "databases", 365 "day_hour", 366 "day_microsecond", 367 "day_minute", 368 "day_second", 369 "dec", 370 "decimal", 371 "declare", 372 "default", 373 "delayed", 374 "delete", 375 "dense_rank", 376 "desc", 377 "describe", 378 "deterministic", 379 "distinct", 380 "distinctrow", 381 "div", 382 "double", 383 "drop", 384 "dual", 385 "each", 386 "else", 387 "elseif", 388 "empty", 389 "enclosed", 390 "escaped", 391 "except", 392 "exists", 393 "exit", 394 "explain", 395 "false", 396 "fetch", 397 "first_value", 398 "float", 399 "float4", 400 "float8", 401 "for", 402 "force", 403 "foreign", 404 "from", 405 "fulltext", 406 "function", 407 "generated", 408 "get", 409 "grant", 410 "group", 411 "grouping", 412 "groups", 413 "having", 414 "high_priority", 415 "hour_microsecond", 416 "hour_minute", 417 "hour_second", 418 "if", 419 "ignore", 420 "in", 421 "index", 422 "infile", 423 "inner", 424 "inout", 425 "insensitive", 426 "insert", 427 "int", 428 "int1", 429 "int2", 430 "int3", 431 "int4", 432 "int8", 433 "integer", 434 "intersect", 435 "interval", 436 "into", 437 "io_after_gtids", 438 "io_before_gtids", 439 "is", 440 "iterate", 441 "join", 442 "json_table", 443 "key", 444 "keys", 445 "kill", 446 "lag", 447 "last_value", 448 "lateral", 449 "lead", 450 "leading", 451 "leave", 452 "left", 453 "like", 454 "limit", 455 "linear", 456 "lines", 457 "load", 458 "localtime", 459 "localtimestamp", 460 "lock", 461 "long", 462 "longblob", 463 "longtext", 464 "loop", 465 "low_priority", 466 "master_bind", 467 "master_ssl_verify_server_cert", 468 "match", 469 "maxvalue", 470 "mediumblob", 471 "mediumint", 472 "mediumtext", 473 "middleint", 474 "minute_microsecond", 475 "minute_second", 476 "mod", 477 "modifies", 478 "natural", 479 "not", 480 "no_write_to_binlog", 481 "nth_value", 482 "ntile", 483 "null", 484 "numeric", 485 "of", 486 "on", 487 "optimize", 488 "optimizer_costs", 489 "option", 490 "optionally", 491 "or", 492 "order", 493 "out", 494 "outer", 495 "outfile", 496 "over", 497 "partition", 498 "percent_rank", 499 "precision", 500 "primary", 501 "procedure", 502 "purge", 503 "range", 504 "rank", 505 "read", 506 "reads", 507 "read_write", 508 "real", 509 "recursive", 510 "references", 511 "regexp", 512 "release", 513 "rename", 514 "repeat", 515 "replace", 516 "require", 517 "resignal", 518 "restrict", 519 "return", 520 "revoke", 521 "right", 522 "rlike", 523 "row", 524 "rows", 525 "row_number", 526 "schema", 527 "schemas", 528 "second_microsecond", 529 "select", 530 "sensitive", 531 "separator", 532 "set", 533 "show", 534 "signal", 535 "smallint", 536 "spatial", 537 "specific", 538 "sql", 539 "sqlexception", 540 "sqlstate", 541 "sqlwarning", 542 "sql_big_result", 543 "sql_calc_found_rows", 544 "sql_small_result", 545 "ssl", 546 "starting", 547 "stored", 548 "straight_join", 549 "system", 550 "table", 551 "terminated", 552 "then", 553 "tinyblob", 554 "tinyint", 555 "tinytext", 556 "to", 557 "trailing", 558 "trigger", 559 "true", 560 "undo", 561 "union", 562 "unique", 563 "unlock", 564 "unsigned", 565 "update", 566 "usage", 567 "use", 568 "using", 569 "utc_date", 570 "utc_time", 571 "utc_timestamp", 572 "values", 573 "varbinary", 574 "varchar", 575 "varcharacter", 576 "varying", 577 "virtual", 578 "when", 579 "where", 580 "while", 581 "window", 582 "with", 583 "write", 584 "xor", 585 "year_month", 586 "zerofill", 587 } 588 589 SQL_SECURITY_VIEW_LOCATION = exp.Properties.Location.POST_CREATE 590 591 def locate_properties(self, properties: exp.Properties) -> defaultdict: 592 locations = super().locate_properties(properties) 593 594 # MySQL puts SQL SECURITY before VIEW but after the schema for functions/procedures 595 if isinstance(create := properties.parent, exp.Create) and create.kind == "VIEW": 596 post_schema = locations[exp.Properties.Location.POST_SCHEMA] 597 for i, p in enumerate(post_schema): 598 if isinstance(p, exp.SqlSecurityProperty): 599 post_schema.pop(i) 600 locations[self.SQL_SECURITY_VIEW_LOCATION].append(p) 601 break 602 603 return locations 604 605 def computedcolumnconstraint_sql(self, expression: exp.ComputedColumnConstraint) -> str: 606 persisted = "STORED" if expression.args.get("persisted") else "VIRTUAL" 607 return f"GENERATED ALWAYS AS ({self.sql(expression.this.unnest())}) {persisted}" 608 609 def array_sql(self, expression: exp.Array) -> str: 610 self.unsupported("Arrays are not supported by MySQL") 611 return self.function_fallback_sql(expression) 612 613 def arraycontainsall_sql(self, expression: exp.ArrayContainsAll) -> str: 614 self.unsupported("Array operations are not supported by MySQL") 615 return self.function_fallback_sql(expression) 616 617 def dpipe_sql(self, expression: exp.DPipe) -> str: 618 return self.func("CONCAT", *expression.flatten()) 619 620 def extract_sql(self, expression: exp.Extract) -> str: 621 unit = expression.name 622 if unit and unit.lower() == "epoch": 623 return self.func("UNIX_TIMESTAMP", expression.expression) 624 625 return super().extract_sql(expression) 626 627 def datatype_sql(self, expression: exp.DataType) -> str: 628 if ( 629 self.VARCHAR_REQUIRES_SIZE 630 and expression.is_type(exp.DType.VARCHAR) 631 and not expression.expressions 632 ): 633 # `VARCHAR` must always have a size - if it doesn't, we always generate `TEXT` 634 return "TEXT" 635 636 # https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html 637 result = super().datatype_sql(expression) 638 if expression.this in self.UNSIGNED_TYPE_MAPPING: 639 result = f"{result} UNSIGNED" 640 641 return result 642 643 def jsonarraycontains_sql(self, expression: exp.JSONArrayContains) -> str: 644 return f"{self.sql(expression, 'this')} MEMBER OF({self.sql(expression, 'expression')})" 645 646 def cast_sql(self, expression: exp.Cast, safe_prefix: str | None = None) -> str: 647 if expression.to.this in self.TIMESTAMP_FUNC_TYPES: 648 return self.func("TIMESTAMP", expression.this) 649 650 to = self.CAST_MAPPING.get(expression.to.this) 651 652 if to: 653 expression.to.set("this", to) 654 return super().cast_sql(expression) 655 656 def show_sql(self, expression: exp.Show) -> str: 657 this = f" {expression.name}" 658 full = " FULL" if expression.args.get("full") else "" 659 global_ = " GLOBAL" if expression.args.get("global_") else "" 660 661 target = self.sql(expression, "target") 662 target = f" {target}" if target else "" 663 if expression.name in ("COLUMNS", "INDEX"): 664 target = f" FROM{target}" 665 elif expression.name == "GRANTS": 666 target = f" FOR{target}" 667 elif expression.name in ("LINKS", "PARTITIONS"): 668 target = f" ON{target}" if target else "" 669 elif expression.name == "PROJECTIONS": 670 target = f" ON TABLE{target}" if target else "" 671 672 db = self._prefixed_sql("FROM", expression, "db") 673 674 like = self._prefixed_sql("LIKE", expression, "like") 675 where = self.sql(expression, "where") 676 677 types = self.expressions(expression, key="types") 678 types = f" {types}" if types else types 679 query = self._prefixed_sql("FOR QUERY", expression, "query") 680 681 if expression.name == "PROFILE": 682 offset = self._prefixed_sql("OFFSET", expression, "offset") 683 limit = self._prefixed_sql("LIMIT", expression, "limit") 684 else: 685 offset = "" 686 limit = self._oldstyle_limit_sql(expression) 687 688 log = self._prefixed_sql("IN", expression, "log") 689 position = self._prefixed_sql("FROM", expression, "position") 690 691 channel = self._prefixed_sql("FOR CHANNEL", expression, "channel") 692 693 if expression.name == "ENGINE": 694 mutex_or_status = " MUTEX" if expression.args.get("mutex") else " STATUS" 695 else: 696 mutex_or_status = "" 697 698 for_table = self._prefixed_sql("FOR TABLE", expression, "for_table") 699 for_group = self._prefixed_sql("FOR GROUP", expression, "for_group") 700 for_user = self._prefixed_sql("FOR USER", expression, "for_user") 701 for_role = self._prefixed_sql("FOR ROLE", expression, "for_role") 702 into_outfile = self._prefixed_sql("INTO OUTFILE", expression, "into_outfile") 703 json = " JSON" if expression.args.get("json") else "" 704 705 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}" 706 707 def alterrename_sql(self, expression: exp.AlterRename, include_to: bool = True) -> str: 708 """To avoid TO keyword in ALTER ... RENAME statements. 709 It's moved from Doris, because it's the same for all MySQL, Doris, and StarRocks. 710 """ 711 return super().alterrename_sql(expression, include_to=False) 712 713 def altercolumn_sql(self, expression: exp.AlterColumn) -> str: 714 dtype = self.sql(expression, "dtype") 715 if not dtype: 716 return super().altercolumn_sql(expression) 717 718 this = self.sql(expression, "this") 719 return f"MODIFY COLUMN {this} {dtype}" 720 721 def _prefixed_sql(self, prefix: str, expression: exp.Expr, arg: str) -> str: 722 sql = self.sql(expression, arg) 723 return f" {prefix} {sql}" if sql else "" 724 725 def _oldstyle_limit_sql(self, expression: exp.Show) -> str: 726 limit = self.sql(expression, "limit") 727 offset = self.sql(expression, "offset") 728 if limit: 729 limit_offset = f"{offset}, {limit}" if offset else limit 730 return f" LIMIT {limit_offset}" 731 return "" 732 733 def timestamptrunc_sql(self, expression: exp.TimestampTrunc) -> str: 734 unit = expression.args.get("unit") 735 736 # Pick an old-enough date to avoid negative timestamp diffs 737 start_ts = "'0000-01-01 00:00:00'" 738 739 # Source: https://stackoverflow.com/a/32955740 740 timestamp_diff = build_date_delta(exp.TimestampDiff)([unit, start_ts, expression.this]) 741 interval = exp.Interval(this=timestamp_diff, unit=unit) 742 dateadd = build_date_delta_with_interval(exp.DateAdd)([start_ts, interval]) 743 744 return self.sql(dateadd) 745 746 def converttimezone_sql(self, expression: exp.ConvertTimezone) -> str: 747 from_tz = expression.args.get("source_tz") 748 to_tz = expression.args.get("target_tz") 749 dt = expression.args.get("timestamp") 750 751 return self.func("CONVERT_TZ", dt, from_tz, to_tz) 752 753 def attimezone_sql(self, expression: exp.AtTimeZone) -> str: 754 self.unsupported("AT TIME ZONE is not supported by MySQL") 755 return self.sql(expression.this) 756 757 def isascii_sql(self, expression: exp.IsAscii) -> str: 758 return f"REGEXP_LIKE({self.sql(expression.this)}, '^[[:ascii:]]*$')" 759 760 def ignorenulls_sql(self, expression: exp.IgnoreNulls) -> str: 761 # https://dev.mysql.com/doc/refman/8.4/en/window-function-descriptions.html 762 self.unsupported("MySQL does not support IGNORE NULLS.") 763 return self.sql(expression.this) 764 765 @unsupported_args("this") 766 def currentschema_sql(self, expression: exp.CurrentSchema) -> str: 767 return self.func("SCHEMA") 768 769 def partition_sql(self, expression: exp.Partition) -> str: 770 parent = expression.parent 771 if isinstance(parent, (exp.PartitionByRangeProperty, exp.PartitionByListProperty)): 772 return self.expressions(expression, flat=True) 773 return super().partition_sql(expression) 774 775 def _partition_by_sql( 776 self, expression: exp.PartitionByRangeProperty | exp.PartitionByListProperty, kind: str 777 ) -> str: 778 partitions = self.expressions(expression, key="partition_expressions", flat=True) 779 create = self.expressions(expression, key="create_expressions", flat=True) 780 return f"PARTITION BY {kind} ({partitions}) ({create})" 781 782 def partitionbyrangeproperty_sql(self, expression: exp.PartitionByRangeProperty) -> str: 783 return self._partition_by_sql(expression, "RANGE") 784 785 def partitionbylistproperty_sql(self, expression: exp.PartitionByListProperty) -> str: 786 return self._partition_by_sql(expression, "LIST") 787 788 def partitionlist_sql(self, expression: exp.PartitionList) -> str: 789 name = self.sql(expression, "this") 790 values = self.expressions(expression, flat=True) 791 return f"PARTITION {name} VALUES IN ({values})" 792 793 def partitionrange_sql(self, expression: exp.PartitionRange) -> str: 794 name = self.sql(expression, "this") 795 values = self.expressions(expression, flat=True) 796 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 116 AFTER_HAVING_MODIFIER_TRANSFORMS = generator.AFTER_HAVING_MODIFIER_TRANSFORMS 117 118 INTERVAL_ALLOWS_PLURAL_FORM = False 119 LOCKING_READS_SUPPORTED = True 120 NULL_ORDERING_SUPPORTED: bool | None = None 121 JOIN_HINTS = False 122 TABLE_HINTS = True 123 DUPLICATE_KEY_UPDATE_WITH_SET = False 124 QUERY_HINT_SEP = " " 125 VALUES_AS_TABLE = False 126 NVL2_SUPPORTED = False 127 LAST_DAY_SUPPORTS_DATE_PART = False 128 JSON_TYPE_REQUIRED_FOR_EXTRACTION = True 129 JSON_PATH_BRACKETED_KEY_SUPPORTED = False 130 JSON_KEY_VALUE_PAIR_SEP = "," 131 SUPPORTS_TO_NUMBER = False 132 PARSE_JSON_NAME: str | None = None 133 PAD_FILL_PATTERN_IS_REQUIRED = True 134 WRAP_DERIVED_VALUES = False 135 VARCHAR_REQUIRES_SIZE = True 136 SUPPORTS_MEDIAN = False 137 UPDATE_STATEMENT_SUPPORTS_FROM = False 138 139 TRANSFORMS = { 140 **generator.Generator.TRANSFORMS, 141 exp.ArrayAgg: rename_func("GROUP_CONCAT"), 142 exp.BitwiseAndAgg: rename_func("BIT_AND"), 143 exp.BitwiseOrAgg: rename_func("BIT_OR"), 144 exp.BitwiseXorAgg: rename_func("BIT_XOR"), 145 exp.BitwiseCount: rename_func("BIT_COUNT"), 146 exp.Chr: lambda self, e: self.chr_sql(e, "CHAR"), 147 exp.CurrentDate: no_paren_current_date_sql, 148 exp.CurrentVersion: rename_func("VERSION"), 149 exp.DateDiff: _remove_ts_or_ds_to_date( 150 lambda self, e: self.func("DATEDIFF", e.this, e.expression), ("this", "expression") 151 ), 152 exp.DateAdd: _remove_ts_or_ds_to_date(date_add_sql("ADD")), 153 exp.DateStrToDate: datestrtodate_sql, 154 exp.DateSub: _remove_ts_or_ds_to_date(date_add_sql("SUB")), 155 exp.DateTrunc: _date_trunc_sql, 156 exp.Day: _remove_ts_or_ds_to_date(), 157 exp.DayOfMonth: _remove_ts_or_ds_to_date(rename_func("DAYOFMONTH")), 158 exp.DayOfWeek: _remove_ts_or_ds_to_date(rename_func("DAYOFWEEK")), 159 exp.DayOfYear: _remove_ts_or_ds_to_date(rename_func("DAYOFYEAR")), 160 exp.GroupConcat: lambda self, e: ( 161 f"""GROUP_CONCAT({self.sql(e, "this")} SEPARATOR {self.sql(e, "separator") or "','"})""" 162 ), 163 exp.ILike: no_ilike_sql, 164 exp.JSONExtractScalar: arrow_json_extract_sql, 165 exp.Length: length_or_char_length_sql, 166 exp.LogicalOr: rename_func("MAX"), 167 exp.LogicalAnd: rename_func("MIN"), 168 exp.Max: max_or_greatest, 169 exp.Min: min_or_least, 170 exp.Month: _remove_ts_or_ds_to_date(), 171 exp.NullSafeEQ: lambda self, e: self.binary(e, "<=>"), 172 exp.NullSafeNEQ: lambda self, e: f"NOT {self.binary(e, '<=>')}", 173 exp.NumberToStr: rename_func("FORMAT"), 174 exp.Pivot: no_pivot_sql, 175 exp.Select: transforms.preprocess( 176 [ 177 transforms.eliminate_distinct_on, 178 transforms.eliminate_semi_and_anti_joins, 179 transforms.eliminate_qualify, 180 transforms.eliminate_full_outer_join, 181 transforms.unnest_generate_date_array_using_recursive_cte, 182 ] 183 ), 184 exp.StrPosition: lambda self, e: strposition_sql( 185 self, e, func_name="LOCATE", supports_position=True 186 ), 187 exp.StrToDate: _str_to_date_sql, 188 exp.StrToTime: _str_to_date_sql, 189 exp.Stuff: rename_func("INSERT"), 190 exp.SessionUser: lambda *_: "SESSION_USER()", 191 exp.TableSample: no_tablesample_sql, 192 exp.TimeFromParts: rename_func("MAKETIME"), 193 exp.TimestampAdd: date_add_interval_sql("DATE", "ADD"), 194 exp.TimestampDiff: lambda self, e: self.func( 195 "TIMESTAMPDIFF", unit_to_var(e), e.expression, e.this 196 ), 197 exp.TimestampSub: date_add_interval_sql("DATE", "SUB"), 198 exp.TimeStrToUnix: rename_func("UNIX_TIMESTAMP"), 199 exp.TimeStrToTime: lambda self, e: timestrtotime_sql( 200 self, 201 e, 202 include_precision=not e.args.get("zone"), 203 ), 204 exp.TimeToStr: _remove_ts_or_ds_to_date( 205 lambda self, e: self.func("DATE_FORMAT", e.this, self.format_time(e)) 206 ), 207 exp.Trim: trim_sql, 208 exp.Trunc: rename_func("TRUNCATE"), 209 exp.TryCast: no_trycast_sql, 210 exp.TsOrDsAdd: date_add_sql("ADD"), 211 exp.TsOrDsDiff: lambda self, e: self.func("DATEDIFF", e.this, e.expression), 212 exp.TsOrDsToDate: _ts_or_ds_to_date_sql, 213 exp.Unicode: lambda self, e: f"ORD(CONVERT({self.sql(e.this)} USING utf32))", 214 exp.UnixToTime: _unix_to_time_sql, 215 exp.Week: _remove_ts_or_ds_to_date(), 216 exp.WeekOfYear: _remove_ts_or_ds_to_date(rename_func("WEEKOFYEAR")), 217 exp.Year: _remove_ts_or_ds_to_date(), 218 exp.UtcTimestamp: rename_func("UTC_TIMESTAMP"), 219 exp.UtcTime: rename_func("UTC_TIME"), 220 } 221 222 UNSIGNED_TYPE_MAPPING = { 223 exp.DType.UBIGINT: "BIGINT", 224 exp.DType.UINT: "INT", 225 exp.DType.UMEDIUMINT: "MEDIUMINT", 226 exp.DType.USMALLINT: "SMALLINT", 227 exp.DType.UTINYINT: "TINYINT", 228 exp.DType.UDECIMAL: "DECIMAL", 229 exp.DType.UDOUBLE: "DOUBLE", 230 } 231 232 TIMESTAMP_TYPE_MAPPING = { 233 exp.DType.DATETIME2: "DATETIME", 234 exp.DType.SMALLDATETIME: "DATETIME", 235 exp.DType.TIMESTAMP: "DATETIME", 236 exp.DType.TIMESTAMPNTZ: "DATETIME", 237 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 238 exp.DType.TIMESTAMPLTZ: "TIMESTAMP", 239 } 240 241 TYPE_MAPPING: t.ClassVar = { 242 exp.DType.NCHAR: "CHAR", 243 exp.DType.NVARCHAR: "VARCHAR", 244 exp.DType.INET: "INET", 245 exp.DType.ROWVERSION: "VARBINARY", 246 exp.DType.UBIGINT: "BIGINT", 247 exp.DType.UINT: "INT", 248 exp.DType.UMEDIUMINT: "MEDIUMINT", 249 exp.DType.USMALLINT: "SMALLINT", 250 exp.DType.UTINYINT: "TINYINT", 251 exp.DType.UDECIMAL: "DECIMAL", 252 exp.DType.UDOUBLE: "DOUBLE", 253 exp.DType.DATETIME2: "DATETIME", 254 exp.DType.SMALLDATETIME: "DATETIME", 255 exp.DType.TIMESTAMP: "DATETIME", 256 exp.DType.TIMESTAMPNTZ: "DATETIME", 257 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 258 exp.DType.TIMESTAMPLTZ: "TIMESTAMP", 259 } 260 261 PROPERTIES_LOCATION: t.ClassVar = { 262 **generator.Generator.PROPERTIES_LOCATION, 263 exp.TransientProperty: exp.Properties.Location.UNSUPPORTED, 264 exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED, 265 exp.PartitionedByProperty: exp.Properties.Location.UNSUPPORTED, 266 exp.PartitionByRangeProperty: exp.Properties.Location.POST_SCHEMA, 267 exp.PartitionByListProperty: exp.Properties.Location.POST_SCHEMA, 268 } 269 270 LIMIT_FETCH = "LIMIT" 271 272 LIMIT_ONLY_LITERALS = True 273 274 CHAR_CAST_MAPPING: t.ClassVar = dict.fromkeys( 275 ( 276 exp.DType.LONGTEXT, 277 exp.DType.LONGBLOB, 278 exp.DType.MEDIUMBLOB, 279 exp.DType.MEDIUMTEXT, 280 exp.DType.TEXT, 281 exp.DType.TINYBLOB, 282 exp.DType.TINYTEXT, 283 exp.DType.VARCHAR, 284 ), 285 "CHAR", 286 ) 287 SIGNED_CAST_MAPPING: t.ClassVar = dict.fromkeys( 288 ( 289 exp.DType.BIGINT, 290 exp.DType.BOOLEAN, 291 exp.DType.INT, 292 exp.DType.SMALLINT, 293 exp.DType.TINYINT, 294 exp.DType.MEDIUMINT, 295 ), 296 "SIGNED", 297 ) 298 299 # MySQL doesn't support many datatypes in cast. 300 # https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html#function_cast 301 CAST_MAPPING = { 302 exp.DType.LONGTEXT: "CHAR", 303 exp.DType.LONGBLOB: "CHAR", 304 exp.DType.MEDIUMBLOB: "CHAR", 305 exp.DType.MEDIUMTEXT: "CHAR", 306 exp.DType.TEXT: "CHAR", 307 exp.DType.TINYBLOB: "CHAR", 308 exp.DType.TINYTEXT: "CHAR", 309 exp.DType.VARCHAR: "CHAR", 310 exp.DType.BIGINT: "SIGNED", 311 exp.DType.BOOLEAN: "SIGNED", 312 exp.DType.INT: "SIGNED", 313 exp.DType.SMALLINT: "SIGNED", 314 exp.DType.TINYINT: "SIGNED", 315 exp.DType.MEDIUMINT: "SIGNED", 316 exp.DType.UBIGINT: "UNSIGNED", 317 } 318 319 TIMESTAMP_FUNC_TYPES = { 320 exp.DType.TIMESTAMPTZ, 321 exp.DType.TIMESTAMPLTZ, 322 } 323 324 # https://dev.mysql.com/doc/refman/8.0/en/keywords.html 325 RESERVED_KEYWORDS = { 326 "accessible", 327 "add", 328 "all", 329 "alter", 330 "analyze", 331 "and", 332 "as", 333 "asc", 334 "asensitive", 335 "before", 336 "between", 337 "bigint", 338 "binary", 339 "blob", 340 "both", 341 "by", 342 "call", 343 "cascade", 344 "case", 345 "change", 346 "char", 347 "character", 348 "check", 349 "collate", 350 "column", 351 "condition", 352 "constraint", 353 "continue", 354 "convert", 355 "create", 356 "cross", 357 "cube", 358 "cume_dist", 359 "current_date", 360 "current_time", 361 "current_timestamp", 362 "current_user", 363 "cursor", 364 "database", 365 "databases", 366 "day_hour", 367 "day_microsecond", 368 "day_minute", 369 "day_second", 370 "dec", 371 "decimal", 372 "declare", 373 "default", 374 "delayed", 375 "delete", 376 "dense_rank", 377 "desc", 378 "describe", 379 "deterministic", 380 "distinct", 381 "distinctrow", 382 "div", 383 "double", 384 "drop", 385 "dual", 386 "each", 387 "else", 388 "elseif", 389 "empty", 390 "enclosed", 391 "escaped", 392 "except", 393 "exists", 394 "exit", 395 "explain", 396 "false", 397 "fetch", 398 "first_value", 399 "float", 400 "float4", 401 "float8", 402 "for", 403 "force", 404 "foreign", 405 "from", 406 "fulltext", 407 "function", 408 "generated", 409 "get", 410 "grant", 411 "group", 412 "grouping", 413 "groups", 414 "having", 415 "high_priority", 416 "hour_microsecond", 417 "hour_minute", 418 "hour_second", 419 "if", 420 "ignore", 421 "in", 422 "index", 423 "infile", 424 "inner", 425 "inout", 426 "insensitive", 427 "insert", 428 "int", 429 "int1", 430 "int2", 431 "int3", 432 "int4", 433 "int8", 434 "integer", 435 "intersect", 436 "interval", 437 "into", 438 "io_after_gtids", 439 "io_before_gtids", 440 "is", 441 "iterate", 442 "join", 443 "json_table", 444 "key", 445 "keys", 446 "kill", 447 "lag", 448 "last_value", 449 "lateral", 450 "lead", 451 "leading", 452 "leave", 453 "left", 454 "like", 455 "limit", 456 "linear", 457 "lines", 458 "load", 459 "localtime", 460 "localtimestamp", 461 "lock", 462 "long", 463 "longblob", 464 "longtext", 465 "loop", 466 "low_priority", 467 "master_bind", 468 "master_ssl_verify_server_cert", 469 "match", 470 "maxvalue", 471 "mediumblob", 472 "mediumint", 473 "mediumtext", 474 "middleint", 475 "minute_microsecond", 476 "minute_second", 477 "mod", 478 "modifies", 479 "natural", 480 "not", 481 "no_write_to_binlog", 482 "nth_value", 483 "ntile", 484 "null", 485 "numeric", 486 "of", 487 "on", 488 "optimize", 489 "optimizer_costs", 490 "option", 491 "optionally", 492 "or", 493 "order", 494 "out", 495 "outer", 496 "outfile", 497 "over", 498 "partition", 499 "percent_rank", 500 "precision", 501 "primary", 502 "procedure", 503 "purge", 504 "range", 505 "rank", 506 "read", 507 "reads", 508 "read_write", 509 "real", 510 "recursive", 511 "references", 512 "regexp", 513 "release", 514 "rename", 515 "repeat", 516 "replace", 517 "require", 518 "resignal", 519 "restrict", 520 "return", 521 "revoke", 522 "right", 523 "rlike", 524 "row", 525 "rows", 526 "row_number", 527 "schema", 528 "schemas", 529 "second_microsecond", 530 "select", 531 "sensitive", 532 "separator", 533 "set", 534 "show", 535 "signal", 536 "smallint", 537 "spatial", 538 "specific", 539 "sql", 540 "sqlexception", 541 "sqlstate", 542 "sqlwarning", 543 "sql_big_result", 544 "sql_calc_found_rows", 545 "sql_small_result", 546 "ssl", 547 "starting", 548 "stored", 549 "straight_join", 550 "system", 551 "table", 552 "terminated", 553 "then", 554 "tinyblob", 555 "tinyint", 556 "tinytext", 557 "to", 558 "trailing", 559 "trigger", 560 "true", 561 "undo", 562 "union", 563 "unique", 564 "unlock", 565 "unsigned", 566 "update", 567 "usage", 568 "use", 569 "using", 570 "utc_date", 571 "utc_time", 572 "utc_timestamp", 573 "values", 574 "varbinary", 575 "varchar", 576 "varcharacter", 577 "varying", 578 "virtual", 579 "when", 580 "where", 581 "while", 582 "window", 583 "with", 584 "write", 585 "xor", 586 "year_month", 587 "zerofill", 588 } 589 590 SQL_SECURITY_VIEW_LOCATION = exp.Properties.Location.POST_CREATE 591 592 def locate_properties(self, properties: exp.Properties) -> defaultdict: 593 locations = super().locate_properties(properties) 594 595 # MySQL puts SQL SECURITY before VIEW but after the schema for functions/procedures 596 if isinstance(create := properties.parent, exp.Create) and create.kind == "VIEW": 597 post_schema = locations[exp.Properties.Location.POST_SCHEMA] 598 for i, p in enumerate(post_schema): 599 if isinstance(p, exp.SqlSecurityProperty): 600 post_schema.pop(i) 601 locations[self.SQL_SECURITY_VIEW_LOCATION].append(p) 602 break 603 604 return locations 605 606 def computedcolumnconstraint_sql(self, expression: exp.ComputedColumnConstraint) -> str: 607 persisted = "STORED" if expression.args.get("persisted") else "VIRTUAL" 608 return f"GENERATED ALWAYS AS ({self.sql(expression.this.unnest())}) {persisted}" 609 610 def array_sql(self, expression: exp.Array) -> str: 611 self.unsupported("Arrays are not supported by MySQL") 612 return self.function_fallback_sql(expression) 613 614 def arraycontainsall_sql(self, expression: exp.ArrayContainsAll) -> str: 615 self.unsupported("Array operations are not supported by MySQL") 616 return self.function_fallback_sql(expression) 617 618 def dpipe_sql(self, expression: exp.DPipe) -> str: 619 return self.func("CONCAT", *expression.flatten()) 620 621 def extract_sql(self, expression: exp.Extract) -> str: 622 unit = expression.name 623 if unit and unit.lower() == "epoch": 624 return self.func("UNIX_TIMESTAMP", expression.expression) 625 626 return super().extract_sql(expression) 627 628 def datatype_sql(self, expression: exp.DataType) -> str: 629 if ( 630 self.VARCHAR_REQUIRES_SIZE 631 and expression.is_type(exp.DType.VARCHAR) 632 and not expression.expressions 633 ): 634 # `VARCHAR` must always have a size - if it doesn't, we always generate `TEXT` 635 return "TEXT" 636 637 # https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html 638 result = super().datatype_sql(expression) 639 if expression.this in self.UNSIGNED_TYPE_MAPPING: 640 result = f"{result} UNSIGNED" 641 642 return result 643 644 def jsonarraycontains_sql(self, expression: exp.JSONArrayContains) -> str: 645 return f"{self.sql(expression, 'this')} MEMBER OF({self.sql(expression, 'expression')})" 646 647 def cast_sql(self, expression: exp.Cast, safe_prefix: str | None = None) -> str: 648 if expression.to.this in self.TIMESTAMP_FUNC_TYPES: 649 return self.func("TIMESTAMP", expression.this) 650 651 to = self.CAST_MAPPING.get(expression.to.this) 652 653 if to: 654 expression.to.set("this", to) 655 return super().cast_sql(expression) 656 657 def show_sql(self, expression: exp.Show) -> str: 658 this = f" {expression.name}" 659 full = " FULL" if expression.args.get("full") else "" 660 global_ = " GLOBAL" if expression.args.get("global_") else "" 661 662 target = self.sql(expression, "target") 663 target = f" {target}" if target else "" 664 if expression.name in ("COLUMNS", "INDEX"): 665 target = f" FROM{target}" 666 elif expression.name == "GRANTS": 667 target = f" FOR{target}" 668 elif expression.name in ("LINKS", "PARTITIONS"): 669 target = f" ON{target}" if target else "" 670 elif expression.name == "PROJECTIONS": 671 target = f" ON TABLE{target}" if target else "" 672 673 db = self._prefixed_sql("FROM", expression, "db") 674 675 like = self._prefixed_sql("LIKE", expression, "like") 676 where = self.sql(expression, "where") 677 678 types = self.expressions(expression, key="types") 679 types = f" {types}" if types else types 680 query = self._prefixed_sql("FOR QUERY", expression, "query") 681 682 if expression.name == "PROFILE": 683 offset = self._prefixed_sql("OFFSET", expression, "offset") 684 limit = self._prefixed_sql("LIMIT", expression, "limit") 685 else: 686 offset = "" 687 limit = self._oldstyle_limit_sql(expression) 688 689 log = self._prefixed_sql("IN", expression, "log") 690 position = self._prefixed_sql("FROM", expression, "position") 691 692 channel = self._prefixed_sql("FOR CHANNEL", expression, "channel") 693 694 if expression.name == "ENGINE": 695 mutex_or_status = " MUTEX" if expression.args.get("mutex") else " STATUS" 696 else: 697 mutex_or_status = "" 698 699 for_table = self._prefixed_sql("FOR TABLE", expression, "for_table") 700 for_group = self._prefixed_sql("FOR GROUP", expression, "for_group") 701 for_user = self._prefixed_sql("FOR USER", expression, "for_user") 702 for_role = self._prefixed_sql("FOR ROLE", expression, "for_role") 703 into_outfile = self._prefixed_sql("INTO OUTFILE", expression, "into_outfile") 704 json = " JSON" if expression.args.get("json") else "" 705 706 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}" 707 708 def alterrename_sql(self, expression: exp.AlterRename, include_to: bool = True) -> str: 709 """To avoid TO keyword in ALTER ... RENAME statements. 710 It's moved from Doris, because it's the same for all MySQL, Doris, and StarRocks. 711 """ 712 return super().alterrename_sql(expression, include_to=False) 713 714 def altercolumn_sql(self, expression: exp.AlterColumn) -> str: 715 dtype = self.sql(expression, "dtype") 716 if not dtype: 717 return super().altercolumn_sql(expression) 718 719 this = self.sql(expression, "this") 720 return f"MODIFY COLUMN {this} {dtype}" 721 722 def _prefixed_sql(self, prefix: str, expression: exp.Expr, arg: str) -> str: 723 sql = self.sql(expression, arg) 724 return f" {prefix} {sql}" if sql else "" 725 726 def _oldstyle_limit_sql(self, expression: exp.Show) -> str: 727 limit = self.sql(expression, "limit") 728 offset = self.sql(expression, "offset") 729 if limit: 730 limit_offset = f"{offset}, {limit}" if offset else limit 731 return f" LIMIT {limit_offset}" 732 return "" 733 734 def timestamptrunc_sql(self, expression: exp.TimestampTrunc) -> str: 735 unit = expression.args.get("unit") 736 737 # Pick an old-enough date to avoid negative timestamp diffs 738 start_ts = "'0000-01-01 00:00:00'" 739 740 # Source: https://stackoverflow.com/a/32955740 741 timestamp_diff = build_date_delta(exp.TimestampDiff)([unit, start_ts, expression.this]) 742 interval = exp.Interval(this=timestamp_diff, unit=unit) 743 dateadd = build_date_delta_with_interval(exp.DateAdd)([start_ts, interval]) 744 745 return self.sql(dateadd) 746 747 def converttimezone_sql(self, expression: exp.ConvertTimezone) -> str: 748 from_tz = expression.args.get("source_tz") 749 to_tz = expression.args.get("target_tz") 750 dt = expression.args.get("timestamp") 751 752 return self.func("CONVERT_TZ", dt, from_tz, to_tz) 753 754 def attimezone_sql(self, expression: exp.AtTimeZone) -> str: 755 self.unsupported("AT TIME ZONE is not supported by MySQL") 756 return self.sql(expression.this) 757 758 def isascii_sql(self, expression: exp.IsAscii) -> str: 759 return f"REGEXP_LIKE({self.sql(expression.this)}, '^[[:ascii:]]*$')" 760 761 def ignorenulls_sql(self, expression: exp.IgnoreNulls) -> str: 762 # https://dev.mysql.com/doc/refman/8.4/en/window-function-descriptions.html 763 self.unsupported("MySQL does not support IGNORE NULLS.") 764 return self.sql(expression.this) 765 766 @unsupported_args("this") 767 def currentschema_sql(self, expression: exp.CurrentSchema) -> str: 768 return self.func("SCHEMA") 769 770 def partition_sql(self, expression: exp.Partition) -> str: 771 parent = expression.parent 772 if isinstance(parent, (exp.PartitionByRangeProperty, exp.PartitionByListProperty)): 773 return self.expressions(expression, flat=True) 774 return super().partition_sql(expression) 775 776 def _partition_by_sql( 777 self, expression: exp.PartitionByRangeProperty | exp.PartitionByListProperty, kind: str 778 ) -> str: 779 partitions = self.expressions(expression, key="partition_expressions", flat=True) 780 create = self.expressions(expression, key="create_expressions", flat=True) 781 return f"PARTITION BY {kind} ({partitions}) ({create})" 782 783 def partitionbyrangeproperty_sql(self, expression: exp.PartitionByRangeProperty) -> str: 784 return self._partition_by_sql(expression, "RANGE") 785 786 def partitionbylistproperty_sql(self, expression: exp.PartitionByListProperty) -> str: 787 return self._partition_by_sql(expression, "LIST") 788 789 def partitionlist_sql(self, expression: exp.PartitionList) -> str: 790 name = self.sql(expression, "this") 791 values = self.expressions(expression, flat=True) 792 return f"PARTITION {name} VALUES IN ({values})" 793 794 def partitionrange_sql(self, expression: exp.PartitionRange) -> str: 795 name = self.sql(expression, "this") 796 values = self.expressions(expression, flat=True) 797 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 =
{'insert', 'call', 'collate', 'bigint', 'get', 'int3', 'release', 'decimal', 'ntile', 'as', 'float8', 'table', 'io_after_gtids', 'primary', 'sqlwarning', 'fulltext', 'last_value', 'real', 'varbinary', 'exit', 'between', 'when', 'recursive', 'float4', 'system', 'write', 'int4', 'databases', 'values', 'purge', 'groups', 'sql_small_result', 'natural', 'sql_big_result', 'high_priority', 'drop', 'infile', 'linear', 'varcharacter', 'references', 'mediumint', 'optimizer_costs', 'each', 'tinyint', 'trigger', 'regexp', 'constraint', 'order', 'lead', 'xor', 'leading', 'enclosed', 'insensitive', 'ssl', 'binary', 'minute_microsecond', 'describe', 'limit', 'cascade', 'procedure', 'replace', 'before', 'no_write_to_binlog', 'utc_time', 'iterate', 'loop', 'outer', 'or', 'lag', 'generated', 'rlike', 'sql_calc_found_rows', 'schema', 'smallint', 'load', 'rename', 'hour_second', 'read', 'repeat', 'separator', 'optimize', 'blob', 'else', 'use', 'cume_dist', 'integer', 'ignore', 'where', 'int8', 'row_number', 'left', 'straight_join', 'all', 'day_hour', 'day_microsecond', 'convert', 'elseif', 'outfile', 'day_minute', 'numeric', 'hour_microsecond', 'master_ssl_verify_server_cert', 'accessible', 'read_write', 'null', 'false', 'from', 'both', 'distinctrow', 'on', 'out', 'deterministic', 'json_table', 'empty', 'div', 'condition', 'match', 'unlock', 'mediumtext', 'default', 'into', 'range', 'over', 'sqlexception', 'having', 'current_user', 'delayed', 'key', 'double', 'signal', 'utc_timestamp', 'using', 'cursor', 'keys', 'unique', 'dual', 'trailing', 'except', 'reads', 'in', 'declare', 'long', 'current_date', 'int2', 'revoke', 'maxvalue', 'require', 'first_value', 'force', 'tinytext', 'not', 'minute_second', 'grouping', 'database', 'longblob', 'union', 'localtime', 'nth_value', 'dense_rank', 'localtimestamp', 'desc', 'show', 'rows', 'index', 'master_bind', 'schemas', 'fetch', 'interval', 'to', 'true', 'change', 'low_priority', 'hour_minute', 'sqlstate', 'tinyblob', 'varchar', 'create', 'delete', 'current_timestamp', 'asc', 'is', 'percent_rank', 'function', 'stored', 'precision', 'leave', 'lock', 'mod', 'asensitive', 'for', 'case', 'year_month', 'option', 'lines', 'column', 'like', 'longtext', 'grant', 'sensitive', 'usage', 'then', 'distinct', 'return', 'select', 'char', 'sql', 'join', 'modifies', 'of', 'day_second', 'cube', 'utc_date', 'unsigned', 'virtual', 'current_time', 'dec', 'resignal', 'set', 'rank', 'alter', 'specific', 'check', 'continue', 'partition', 'analyze', 'foreign', 'middleint', 'update', 'character', 'optionally', 'varying', 'explain', 'kill', 'exists', 'inner', 'cross', 'int', 'window', 'spatial', 'row', 'undo', 'io_before_gtids', 'with', 'right', 'second_microsecond', 'mediumblob', 'terminated', 'escaped', 'zerofill', 'intersect', 'int1', 'lateral', 'and', 'inout', 'group', 'by', 'add', 'float', 'restrict', 'if', 'while', 'starting'}
def
locate_properties( self, properties: sqlglot.expressions.properties.Properties) -> collections.defaultdict:
592 def locate_properties(self, properties: exp.Properties) -> defaultdict: 593 locations = super().locate_properties(properties) 594 595 # MySQL puts SQL SECURITY before VIEW but after the schema for functions/procedures 596 if isinstance(create := properties.parent, exp.Create) and create.kind == "VIEW": 597 post_schema = locations[exp.Properties.Location.POST_SCHEMA] 598 for i, p in enumerate(post_schema): 599 if isinstance(p, exp.SqlSecurityProperty): 600 post_schema.pop(i) 601 locations[self.SQL_SECURITY_VIEW_LOCATION].append(p) 602 break 603 604 return locations
def
computedcolumnconstraint_sql( self, expression: sqlglot.expressions.constraints.ComputedColumnConstraint) -> str:
628 def datatype_sql(self, expression: exp.DataType) -> str: 629 if ( 630 self.VARCHAR_REQUIRES_SIZE 631 and expression.is_type(exp.DType.VARCHAR) 632 and not expression.expressions 633 ): 634 # `VARCHAR` must always have a size - if it doesn't, we always generate `TEXT` 635 return "TEXT" 636 637 # https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html 638 result = super().datatype_sql(expression) 639 if expression.this in self.UNSIGNED_TYPE_MAPPING: 640 result = f"{result} UNSIGNED" 641 642 return result
def
cast_sql( self, expression: sqlglot.expressions.functions.Cast, safe_prefix: str | None = None) -> str:
647 def cast_sql(self, expression: exp.Cast, safe_prefix: str | None = None) -> str: 648 if expression.to.this in self.TIMESTAMP_FUNC_TYPES: 649 return self.func("TIMESTAMP", expression.this) 650 651 to = self.CAST_MAPPING.get(expression.to.this) 652 653 if to: 654 expression.to.set("this", to) 655 return super().cast_sql(expression)
657 def show_sql(self, expression: exp.Show) -> str: 658 this = f" {expression.name}" 659 full = " FULL" if expression.args.get("full") else "" 660 global_ = " GLOBAL" if expression.args.get("global_") else "" 661 662 target = self.sql(expression, "target") 663 target = f" {target}" if target else "" 664 if expression.name in ("COLUMNS", "INDEX"): 665 target = f" FROM{target}" 666 elif expression.name == "GRANTS": 667 target = f" FOR{target}" 668 elif expression.name in ("LINKS", "PARTITIONS"): 669 target = f" ON{target}" if target else "" 670 elif expression.name == "PROJECTIONS": 671 target = f" ON TABLE{target}" if target else "" 672 673 db = self._prefixed_sql("FROM", expression, "db") 674 675 like = self._prefixed_sql("LIKE", expression, "like") 676 where = self.sql(expression, "where") 677 678 types = self.expressions(expression, key="types") 679 types = f" {types}" if types else types 680 query = self._prefixed_sql("FOR QUERY", expression, "query") 681 682 if expression.name == "PROFILE": 683 offset = self._prefixed_sql("OFFSET", expression, "offset") 684 limit = self._prefixed_sql("LIMIT", expression, "limit") 685 else: 686 offset = "" 687 limit = self._oldstyle_limit_sql(expression) 688 689 log = self._prefixed_sql("IN", expression, "log") 690 position = self._prefixed_sql("FROM", expression, "position") 691 692 channel = self._prefixed_sql("FOR CHANNEL", expression, "channel") 693 694 if expression.name == "ENGINE": 695 mutex_or_status = " MUTEX" if expression.args.get("mutex") else " STATUS" 696 else: 697 mutex_or_status = "" 698 699 for_table = self._prefixed_sql("FOR TABLE", expression, "for_table") 700 for_group = self._prefixed_sql("FOR GROUP", expression, "for_group") 701 for_user = self._prefixed_sql("FOR USER", expression, "for_user") 702 for_role = self._prefixed_sql("FOR ROLE", expression, "for_role") 703 into_outfile = self._prefixed_sql("INTO OUTFILE", expression, "into_outfile") 704 json = " JSON" if expression.args.get("json") else "" 705 706 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:
708 def alterrename_sql(self, expression: exp.AlterRename, include_to: bool = True) -> str: 709 """To avoid TO keyword in ALTER ... RENAME statements. 710 It's moved from Doris, because it's the same for all MySQL, Doris, and StarRocks. 711 """ 712 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.
734 def timestamptrunc_sql(self, expression: exp.TimestampTrunc) -> str: 735 unit = expression.args.get("unit") 736 737 # Pick an old-enough date to avoid negative timestamp diffs 738 start_ts = "'0000-01-01 00:00:00'" 739 740 # Source: https://stackoverflow.com/a/32955740 741 timestamp_diff = build_date_delta(exp.TimestampDiff)([unit, start_ts, expression.this]) 742 interval = exp.Interval(this=timestamp_diff, unit=unit) 743 dateadd = build_date_delta_with_interval(exp.DateAdd)([start_ts, interval]) 744 745 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
- 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
- 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
- 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
- alterindex_sql
- alterdiststyle_sql
- altersortkey_sql
- renamecolumn_sql
- alterset_sql
- alter_sql
- altersession_sql
- add_column_sql
- droppartition_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