sqlglot.generators.mysql
1from __future__ import annotations 2 3import typing as t 4 5from sqlglot import exp, generator, transforms 6from sqlglot.dialects.dialect import ( 7 arrow_json_extract_sql, 8 build_date_delta, 9 build_date_delta_with_interval, 10 date_add_interval_sql, 11 datestrtodate_sql, 12 length_or_char_length_sql, 13 max_or_greatest, 14 min_or_least, 15 no_ilike_sql, 16 no_paren_current_date_sql, 17 no_pivot_sql, 18 no_tablesample_sql, 19 no_trycast_sql, 20 if_sql, 21 remove_ts_or_ds_to_date, 22 rename_func, 23 strposition_sql, 24 unit_to_var, 25 trim_sql, 26 timestrtotime_sql, 27) 28from sqlglot.generator import unsupported_args 29from collections import defaultdict 30 31 32def _date_trunc_sql(self: MySQLGenerator, expression: exp.DateTrunc) -> str: 33 expr = self.sql(expression, "this") 34 unit_expr = expression.args.get("unit") 35 unit = ( 36 self.weekstart_name(unit_expr) 37 if isinstance(unit_expr, exp.WeekStart) 38 else expression.text("unit").upper() 39 ) 40 41 if unit == "WEEK": 42 concat = f"CONCAT(YEAR({expr}), ' ', WEEK({expr}, 1), ' 1')" 43 date_format = "%Y %u %w" 44 elif unit == "MONTH": 45 concat = f"CONCAT(YEAR({expr}), ' ', MONTH({expr}), ' 1')" 46 date_format = "%Y %c %e" 47 elif unit == "QUARTER": 48 concat = f"CONCAT(YEAR({expr}), ' ', QUARTER({expr}) * 3 - 2, ' 1')" 49 date_format = "%Y %c %e" 50 elif unit == "YEAR": 51 concat = f"CONCAT(YEAR({expr}), ' 1 1')" 52 date_format = "%Y %c %e" 53 else: 54 if unit != "DAY": 55 self.unsupported(f"Unexpected interval unit: {unit}") 56 return self.func("DATE", expr) 57 58 return self.func("STR_TO_DATE", concat, f"'{date_format}'") 59 60 61def _str_to_date_sql( 62 self: MySQLGenerator, expression: exp.StrToDate | exp.StrToTime | exp.TsOrDsToDate 63) -> str: 64 return self.func("STR_TO_DATE", expression.this, self.format_time(expression)) 65 66 67def _unix_to_time_sql(self: MySQLGenerator, expression: exp.UnixToTime) -> str: 68 scale = expression.args.get("scale") 69 timestamp = expression.this 70 71 if scale in (None, exp.UnixToTime.SECONDS): 72 return self.func("FROM_UNIXTIME", timestamp, self.format_time(expression)) 73 74 return self.func( 75 "FROM_UNIXTIME", 76 exp.Div(this=timestamp, expression=exp.func("POW", 10, scale)), 77 self.format_time(expression), 78 ) 79 80 81def date_add_sql( 82 kind: str, 83) -> t.Callable[[generator.Generator, exp.Expr], str]: 84 def func(self: generator.Generator, expression: exp.Expr) -> str: 85 return self.func( 86 f"DATE_{kind}", 87 expression.this, 88 exp.Interval(this=expression.expression, unit=unit_to_var(expression)), 89 ) 90 91 return func 92 93 94_MAKE_INTERVAL_UNIT_ALIASES = { 95 "years": "year", 96 "months": "month", 97 "weeks": "week", 98 "days": "day", 99 "hours": "hour", 100 "minutes": "minute", 101 "mins": "minute", 102 "seconds": "second", 103 "secs": "second", 104} 105 106 107def _ts_or_ds_to_date_sql(self: MySQLGenerator, expression: exp.TsOrDsToDate) -> str: 108 time_format = expression.args.get("format") 109 return _str_to_date_sql(self, expression) if time_format else self.func("DATE", expression.this) 110 111 112class MySQLGenerator(generator.Generator): 113 SELECT_KINDS: tuple[str, ...] = () 114 TRY_SUPPORTED = False 115 SUPPORTS_UESCAPE = False 116 SUPPORTS_DECODE_CASE = False 117 SUPPORTS_MODIFY_COLUMN = True 118 SUPPORTS_CHANGE_COLUMN = True 119 SUPPORTS_ALTER_COLUMN_NULLABILITY = True 120 121 AFTER_HAVING_MODIFIER_TRANSFORMS = generator.AFTER_HAVING_MODIFIER_TRANSFORMS 122 123 INTERVAL_ALLOWS_PLURAL_FORM = False 124 LOCKING_READS_SUPPORTED = True 125 NULL_ORDERING_SUPPORTED: bool | None = None 126 JOIN_HINTS = False 127 TABLE_HINTS = True 128 DUPLICATE_KEY_UPDATE_WITH_SET = False 129 QUERY_HINT_SEP = " " 130 VALUES_AS_TABLE = False 131 NVL2_SUPPORTED = False 132 LAST_DAY_SUPPORTS_DATE_PART = False 133 JSON_TYPE_REQUIRED_FOR_EXTRACTION = True 134 JSON_PATH_BRACKETED_KEY_SUPPORTED = False 135 JSON_KEY_VALUE_PAIR_SEP = "," 136 SUPPORTS_TO_NUMBER = False 137 PARSE_JSON_NAME: str | None = None 138 PAD_FILL_PATTERN_IS_REQUIRED = True 139 WRAP_DERIVED_VALUES = False 140 VARCHAR_REQUIRES_SIZE = True 141 SUPPORTS_MEDIAN = False 142 UPDATE_STATEMENT_SUPPORTS_FROM = False 143 144 TRANSFORMS = { 145 **generator.Generator.TRANSFORMS, 146 exp.ArrayAgg: rename_func("GROUP_CONCAT"), 147 exp.BitwiseAndAgg: rename_func("BIT_AND"), 148 exp.BitwiseOrAgg: rename_func("BIT_OR"), 149 exp.BitwiseXorAgg: rename_func("BIT_XOR"), 150 exp.BitwiseCount: rename_func("BIT_COUNT"), 151 exp.Chr: lambda self, e: self.chr_sql(e, "CHAR"), 152 exp.CurrentDate: no_paren_current_date_sql, 153 exp.CurrentVersion: rename_func("VERSION"), 154 exp.DateDiff: remove_ts_or_ds_to_date( 155 lambda self, e: self.func("DATEDIFF", e.this, e.expression), ("this", "expression") 156 ), 157 exp.DateAdd: date_add_sql("ADD"), 158 exp.DateStrToDate: datestrtodate_sql, 159 exp.DateSub: date_add_sql("SUB"), 160 exp.DateTrunc: _date_trunc_sql, 161 exp.Day: remove_ts_or_ds_to_date(), 162 exp.DayOfMonth: remove_ts_or_ds_to_date(rename_func("DAYOFMONTH")), 163 exp.DayOfWeek: remove_ts_or_ds_to_date(rename_func("DAYOFWEEK")), 164 exp.DayOfYear: remove_ts_or_ds_to_date(rename_func("DAYOFYEAR")), 165 exp.GroupConcat: lambda self, e: ( 166 f"""GROUP_CONCAT({self.sql(e, "this")} SEPARATOR {self.sql(e, "separator") or "','"})""" 167 ), 168 exp.ILike: no_ilike_sql, 169 # https://dev.mysql.com/doc/refman/9.7/en/flow-control-functions.html#function_if 170 exp.If: if_sql(false_value="NULL"), 171 exp.JSONExtractScalar: arrow_json_extract_sql, 172 exp.Length: length_or_char_length_sql, 173 exp.LogicalOr: rename_func("MAX"), 174 exp.LogicalAnd: rename_func("MIN"), 175 exp.Max: max_or_greatest, 176 exp.Min: min_or_least, 177 exp.Month: remove_ts_or_ds_to_date(), 178 exp.NullSafeEQ: lambda self, e: self.binary(e, "<=>"), 179 exp.NullSafeNEQ: lambda self, e: f"NOT {self.binary(e, '<=>')}", 180 exp.NumberToStr: rename_func("FORMAT"), 181 exp.Pivot: no_pivot_sql, 182 exp.Select: transforms.preprocess( 183 [ 184 transforms.eliminate_distinct_on, 185 transforms.eliminate_semi_and_anti_joins, 186 transforms.eliminate_qualify, 187 transforms.eliminate_full_outer_join, 188 transforms.unnest_generate_date_array_using_recursive_cte, 189 ] 190 ), 191 exp.StrPosition: lambda self, e: strposition_sql( 192 self, e, func_name="LOCATE", supports_position=True 193 ), 194 exp.StrToDate: _str_to_date_sql, 195 exp.StrToTime: _str_to_date_sql, 196 exp.Stuff: rename_func("INSERT"), 197 exp.SessionUser: lambda *_: "SESSION_USER()", 198 exp.TableSample: no_tablesample_sql, 199 exp.TimeFromParts: rename_func("MAKETIME"), 200 exp.TimestampAdd: date_add_interval_sql("DATE", "ADD"), 201 exp.TimestampDiff: lambda self, e: self.func( 202 "TIMESTAMPDIFF", unit_to_var(e), e.expression, e.this 203 ), 204 exp.TimestampSub: date_add_interval_sql("DATE", "SUB"), 205 exp.TimeStrToUnix: rename_func("UNIX_TIMESTAMP"), 206 exp.TimeStrToTime: lambda self, e: timestrtotime_sql( 207 self, 208 e, 209 include_precision=not e.args.get("zone"), 210 ), 211 exp.TimeToStr: remove_ts_or_ds_to_date( 212 lambda self, e: self.func("DATE_FORMAT", e.this, self.format_time(e)) 213 ), 214 exp.Trim: trim_sql, 215 exp.Trunc: rename_func("TRUNCATE"), 216 exp.TryCast: no_trycast_sql, 217 exp.TsOrDsAdd: date_add_sql("ADD"), 218 exp.TsOrDsDiff: lambda self, e: self.func("DATEDIFF", e.this, e.expression), 219 exp.TsOrDsToDate: _ts_or_ds_to_date_sql, 220 exp.Unicode: lambda self, e: f"ORD(CONVERT({self.sql(e.this)} USING utf32))", 221 exp.UnixToTime: _unix_to_time_sql, 222 exp.Week: remove_ts_or_ds_to_date(), 223 exp.WeekOfYear: remove_ts_or_ds_to_date(rename_func("WEEKOFYEAR")), 224 exp.Year: remove_ts_or_ds_to_date(), 225 exp.UtcTimestamp: rename_func("UTC_TIMESTAMP"), 226 exp.UtcTime: rename_func("UTC_TIME"), 227 } 228 229 UNSIGNED_TYPE_MAPPING: t.ClassVar = { 230 exp.DType.UBIGINT: "BIGINT", 231 exp.DType.UINT: "INT", 232 exp.DType.UMEDIUMINT: "MEDIUMINT", 233 exp.DType.USMALLINT: "SMALLINT", 234 exp.DType.UTINYINT: "TINYINT", 235 exp.DType.UDECIMAL: "DECIMAL", 236 exp.DType.UDOUBLE: "DOUBLE", 237 } 238 239 TIMESTAMP_TYPE_MAPPING: t.ClassVar = { 240 exp.DType.DATETIME2: "DATETIME", 241 exp.DType.SMALLDATETIME: "DATETIME", 242 exp.DType.TIMESTAMP: "DATETIME", 243 exp.DType.TIMESTAMPNTZ: "DATETIME", 244 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 245 exp.DType.TIMESTAMPLTZ: "TIMESTAMP", 246 } 247 248 TYPE_MAPPING: t.ClassVar = { 249 exp.DType.NCHAR: "CHAR", 250 exp.DType.NVARCHAR: "VARCHAR", 251 exp.DType.INET: "INET", 252 exp.DType.ROWVERSION: "VARBINARY", 253 exp.DType.UBIGINT: "BIGINT", 254 exp.DType.UINT: "INT", 255 exp.DType.UMEDIUMINT: "MEDIUMINT", 256 exp.DType.USMALLINT: "SMALLINT", 257 exp.DType.UTINYINT: "TINYINT", 258 exp.DType.UDECIMAL: "DECIMAL", 259 exp.DType.UDOUBLE: "DOUBLE", 260 exp.DType.DATETIME2: "DATETIME", 261 exp.DType.SMALLDATETIME: "DATETIME", 262 exp.DType.TIMESTAMP: "DATETIME", 263 exp.DType.TIMESTAMPNTZ: "DATETIME", 264 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 265 exp.DType.TIMESTAMPLTZ: "TIMESTAMP", 266 } 267 268 PROPERTIES_LOCATION: t.ClassVar = { 269 **generator.Generator.PROPERTIES_LOCATION, 270 exp.TransientProperty: exp.Properties.Location.UNSUPPORTED, 271 exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED, 272 exp.PartitionedByProperty: exp.Properties.Location.UNSUPPORTED, 273 exp.PartitionByRangeProperty: exp.Properties.Location.POST_SCHEMA, 274 exp.PartitionByListProperty: exp.Properties.Location.POST_SCHEMA, 275 } 276 277 LIMIT_FETCH = "LIMIT" 278 279 LIMIT_ONLY_LITERALS = True 280 281 CHAR_CAST_MAPPING: t.ClassVar = dict.fromkeys( 282 ( 283 exp.DType.LONGTEXT, 284 exp.DType.LONGBLOB, 285 exp.DType.MEDIUMBLOB, 286 exp.DType.MEDIUMTEXT, 287 exp.DType.TEXT, 288 exp.DType.TINYBLOB, 289 exp.DType.TINYTEXT, 290 exp.DType.VARCHAR, 291 ), 292 "CHAR", 293 ) 294 SIGNED_CAST_MAPPING: t.ClassVar = dict.fromkeys( 295 ( 296 exp.DType.BIGINT, 297 exp.DType.BOOLEAN, 298 exp.DType.INT, 299 exp.DType.SMALLINT, 300 exp.DType.TINYINT, 301 exp.DType.MEDIUMINT, 302 ), 303 "SIGNED", 304 ) 305 306 # MySQL doesn't support many datatypes in cast. 307 # https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html#function_cast 308 CAST_MAPPING: t.ClassVar = { 309 exp.DType.LONGTEXT: "CHAR", 310 exp.DType.LONGBLOB: "CHAR", 311 exp.DType.MEDIUMBLOB: "CHAR", 312 exp.DType.MEDIUMTEXT: "CHAR", 313 exp.DType.TEXT: "CHAR", 314 exp.DType.TINYBLOB: "CHAR", 315 exp.DType.TINYTEXT: "CHAR", 316 exp.DType.VARCHAR: "CHAR", 317 exp.DType.BIGINT: "SIGNED", 318 exp.DType.BOOLEAN: "SIGNED", 319 exp.DType.INT: "SIGNED", 320 exp.DType.SMALLINT: "SIGNED", 321 exp.DType.TINYINT: "SIGNED", 322 exp.DType.MEDIUMINT: "SIGNED", 323 exp.DType.UBIGINT: "UNSIGNED", 324 } 325 326 TIMESTAMP_FUNC_TYPES: t.ClassVar = { 327 exp.DType.TIMESTAMPTZ, 328 exp.DType.TIMESTAMPLTZ, 329 } 330 331 # https://dev.mysql.com/doc/refman/8.0/en/keywords.html 332 RESERVED_KEYWORDS = { 333 "accessible", 334 "add", 335 "all", 336 "alter", 337 "analyze", 338 "and", 339 "as", 340 "asc", 341 "asensitive", 342 "before", 343 "between", 344 "bigint", 345 "binary", 346 "blob", 347 "both", 348 "by", 349 "call", 350 "cascade", 351 "case", 352 "change", 353 "char", 354 "character", 355 "check", 356 "collate", 357 "column", 358 "condition", 359 "constraint", 360 "continue", 361 "convert", 362 "create", 363 "cross", 364 "cube", 365 "cume_dist", 366 "current_date", 367 "current_time", 368 "current_timestamp", 369 "current_user", 370 "cursor", 371 "database", 372 "databases", 373 "day_hour", 374 "day_microsecond", 375 "day_minute", 376 "day_second", 377 "dec", 378 "decimal", 379 "declare", 380 "default", 381 "delayed", 382 "delete", 383 "dense_rank", 384 "desc", 385 "describe", 386 "deterministic", 387 "distinct", 388 "distinctrow", 389 "div", 390 "double", 391 "drop", 392 "dual", 393 "each", 394 "else", 395 "elseif", 396 "empty", 397 "enclosed", 398 "escaped", 399 "except", 400 "exists", 401 "exit", 402 "explain", 403 "false", 404 "fetch", 405 "first_value", 406 "float", 407 "float4", 408 "float8", 409 "for", 410 "force", 411 "foreign", 412 "from", 413 "fulltext", 414 "function", 415 "generated", 416 "get", 417 "grant", 418 "group", 419 "grouping", 420 "groups", 421 "having", 422 "high_priority", 423 "hour_microsecond", 424 "hour_minute", 425 "hour_second", 426 "if", 427 "ignore", 428 "in", 429 "index", 430 "infile", 431 "inner", 432 "inout", 433 "insensitive", 434 "insert", 435 "int", 436 "int1", 437 "int2", 438 "int3", 439 "int4", 440 "int8", 441 "integer", 442 "intersect", 443 "interval", 444 "into", 445 "io_after_gtids", 446 "io_before_gtids", 447 "is", 448 "iterate", 449 "join", 450 "json_table", 451 "key", 452 "keys", 453 "kill", 454 "lag", 455 "last_value", 456 "lateral", 457 "lead", 458 "leading", 459 "leave", 460 "left", 461 "like", 462 "limit", 463 "linear", 464 "lines", 465 "load", 466 "localtime", 467 "localtimestamp", 468 "lock", 469 "long", 470 "longblob", 471 "longtext", 472 "loop", 473 "low_priority", 474 "master_bind", 475 "master_ssl_verify_server_cert", 476 "match", 477 "maxvalue", 478 "mediumblob", 479 "mediumint", 480 "mediumtext", 481 "middleint", 482 "minute_microsecond", 483 "minute_second", 484 "mod", 485 "modifies", 486 "natural", 487 "not", 488 "no_write_to_binlog", 489 "nth_value", 490 "ntile", 491 "null", 492 "numeric", 493 "of", 494 "on", 495 "optimize", 496 "optimizer_costs", 497 "option", 498 "optionally", 499 "or", 500 "order", 501 "out", 502 "outer", 503 "outfile", 504 "over", 505 "partition", 506 "percent_rank", 507 "precision", 508 "primary", 509 "procedure", 510 "purge", 511 "range", 512 "rank", 513 "read", 514 "reads", 515 "read_write", 516 "real", 517 "recursive", 518 "references", 519 "regexp", 520 "release", 521 "rename", 522 "repeat", 523 "replace", 524 "require", 525 "resignal", 526 "restrict", 527 "return", 528 "revoke", 529 "right", 530 "rlike", 531 "row", 532 "rows", 533 "row_number", 534 "schema", 535 "schemas", 536 "second_microsecond", 537 "select", 538 "sensitive", 539 "separator", 540 "set", 541 "show", 542 "signal", 543 "smallint", 544 "spatial", 545 "specific", 546 "sql", 547 "sqlexception", 548 "sqlstate", 549 "sqlwarning", 550 "sql_big_result", 551 "sql_calc_found_rows", 552 "sql_small_result", 553 "ssl", 554 "starting", 555 "stored", 556 "straight_join", 557 "system", 558 "table", 559 "terminated", 560 "then", 561 "tinyblob", 562 "tinyint", 563 "tinytext", 564 "to", 565 "trailing", 566 "trigger", 567 "true", 568 "undo", 569 "union", 570 "unique", 571 "unlock", 572 "unsigned", 573 "update", 574 "usage", 575 "use", 576 "using", 577 "utc_date", 578 "utc_time", 579 "utc_timestamp", 580 "values", 581 "varbinary", 582 "varchar", 583 "varcharacter", 584 "varying", 585 "virtual", 586 "when", 587 "where", 588 "while", 589 "window", 590 "with", 591 "write", 592 "xor", 593 "year_month", 594 "zerofill", 595 } 596 597 SQL_SECURITY_VIEW_LOCATION: t.ClassVar = exp.Properties.Location.POST_CREATE 598 599 def makeinterval_sql(self: MySQLGenerator, expression: exp.MakeInterval) -> str: 600 intervals: list[exp.Interval] = [] 601 for arg_key, value in expression.args.items(): 602 if value is None: 603 continue 604 605 if isinstance(value, exp.Kwarg): 606 unit_name = _MAKE_INTERVAL_UNIT_ALIASES.get( 607 value.this.name.lower(), value.this.name.lower() 608 ) 609 value = value.expression 610 else: 611 unit_name = arg_key 612 613 intervals.append(exp.Interval(this=value.copy(), unit=exp.var(unit_name.upper()))) 614 615 if not intervals: 616 return self.function_fallback_sql(expression) 617 618 parent = expression.parent 619 sep = " - " if isinstance(parent, exp.Sub) and parent.expression is expression else " + " 620 621 return sep.join(self.sql(interval) for interval in intervals) 622 623 def locate_properties(self, properties: exp.Properties) -> defaultdict: 624 locations = super().locate_properties(properties) 625 626 # MySQL puts SQL SECURITY before VIEW but after the schema for functions/procedures 627 if isinstance(create := properties.parent, exp.Create) and create.kind == "VIEW": 628 post_schema = locations[exp.Properties.Location.POST_SCHEMA] 629 for i, p in enumerate(post_schema): 630 if isinstance(p, exp.SqlSecurityProperty): 631 post_schema.pop(i) 632 locations[self.SQL_SECURITY_VIEW_LOCATION].append(p) 633 break 634 635 return locations 636 637 def computedcolumnconstraint_sql(self, expression: exp.ComputedColumnConstraint) -> str: 638 persisted = "STORED" if expression.args.get("persisted") else "VIRTUAL" 639 return f"GENERATED ALWAYS AS ({self.sql(expression.this.unnest())}) {persisted}" 640 641 def array_sql(self, expression: exp.Array) -> str: 642 self.unsupported("Arrays are not supported by MySQL") 643 return self.function_fallback_sql(expression) 644 645 def arraycontainsall_sql(self, expression: exp.ArrayContainsAll) -> str: 646 self.unsupported("Array operations are not supported by MySQL") 647 return self.function_fallback_sql(expression) 648 649 def arraycontainedby_sql(self, expression: exp.ArrayContainedBy) -> str: 650 self.unsupported("Array operations are not supported by MySQL") 651 return self.function_fallback_sql(expression) 652 653 def dpipe_sql(self, expression: exp.DPipe) -> str: 654 return self.func("CONCAT", *expression.flatten()) 655 656 def extract_sql(self, expression: exp.Extract) -> str: 657 unit = expression.name 658 if unit and unit.lower() == "epoch": 659 return self.func("UNIX_TIMESTAMP", expression.expression) 660 661 return super().extract_sql(expression) 662 663 def datatype_sql(self, expression: exp.DataType) -> str: 664 if ( 665 self.VARCHAR_REQUIRES_SIZE 666 and expression.is_type(exp.DType.VARCHAR) 667 and not expression.expressions 668 ): 669 # `VARCHAR` must always have a size - if it doesn't, we always generate `TEXT` 670 return "TEXT" 671 672 # https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html 673 result = super().datatype_sql(expression) 674 if expression.this in self.UNSIGNED_TYPE_MAPPING: 675 result = f"{result} UNSIGNED" 676 677 return result 678 679 def jsonarraycontains_sql(self, expression: exp.JSONArrayContains) -> str: 680 return f"{self.sql(expression, 'this')} MEMBER OF({self.sql(expression, 'expression')})" 681 682 def cast_sql(self, expression: exp.Cast, safe_prefix: str | None = None) -> str: 683 if expression.to.this in self.TIMESTAMP_FUNC_TYPES: 684 return self.func("TIMESTAMP", expression.this) 685 686 to = self.CAST_MAPPING.get(expression.to.this) 687 688 if to: 689 expression.to.set("this", to) 690 return super().cast_sql(expression) 691 692 def show_sql(self, expression: exp.Show) -> str: 693 this = f" {expression.name}" 694 full = " FULL" if expression.args.get("full") else "" 695 global_ = " GLOBAL" if expression.args.get("global_") else "" 696 697 target = self.sql(expression, "target") 698 699 # SHOW CREATE ... takes a possibly qualified name, it has no FROM clause 700 # https://dev.mysql.com/doc/refman/8.4/en/show-create-table.html 701 if expression.name.startswith("CREATE") and (db_id := self.sql(expression, "db")): 702 target = f"{db_id}.{target}" 703 db = "" 704 else: 705 db = self._prefixed_sql("FROM", expression, "db") 706 707 target = f" {target}" if target else "" 708 if expression.name in ("COLUMNS", "INDEX"): 709 target = f" FROM{target}" 710 elif expression.name == "GRANTS": 711 target = f" FOR{target}" 712 elif expression.name in ("LINKS", "PARTITIONS"): 713 target = f" ON{target}" if target else "" 714 elif expression.name == "PROJECTIONS": 715 target = f" ON TABLE{target}" if target else "" 716 717 like = self._prefixed_sql("LIKE", expression, "like") 718 where = self.sql(expression, "where") 719 720 types = self.expressions(expression, key="types") 721 types = f" {types}" if types else types 722 query = self._prefixed_sql("FOR QUERY", expression, "query") 723 724 if expression.name == "PROFILE": 725 offset = self._prefixed_sql("OFFSET", expression, "offset") 726 limit = self._prefixed_sql("LIMIT", expression, "limit") 727 else: 728 offset = "" 729 limit = self._oldstyle_limit_sql(expression) 730 731 log = self._prefixed_sql("IN", expression, "log") 732 position = self._prefixed_sql("FROM", expression, "position") 733 734 channel = self._prefixed_sql("FOR CHANNEL", expression, "channel") 735 736 if expression.name == "ENGINE": 737 mutex_or_status = " MUTEX" if expression.args.get("mutex") else " STATUS" 738 else: 739 mutex_or_status = "" 740 741 for_table = self._prefixed_sql("FOR TABLE", expression, "for_table") 742 for_group = self._prefixed_sql("FOR GROUP", expression, "for_group") 743 for_user = self._prefixed_sql("FOR USER", expression, "for_user") 744 for_role = self._prefixed_sql("FOR ROLE", expression, "for_role") 745 into_outfile = self._prefixed_sql("INTO OUTFILE", expression, "into_outfile") 746 json = " JSON" if expression.args.get("json") else "" 747 748 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}" 749 750 def alterrename_sql(self, expression: exp.AlterRename, include_to: bool = True) -> str: 751 """To avoid TO keyword in ALTER ... RENAME statements. 752 It's moved from Doris, because it's the same for all MySQL, Doris, and StarRocks. 753 """ 754 return super().alterrename_sql(expression, include_to=False) 755 756 def altercolumn_sql(self, expression: exp.AlterColumn) -> str: 757 dtype = self.sql(expression, "dtype") 758 if not dtype: 759 return super().altercolumn_sql(expression) 760 761 if expression.args.get("exists"): 762 self.unsupported("ALTER COLUMN IF EXISTS is not supported by this dialect") 763 764 this = self.sql(expression, "this") 765 null_constraint = self._alter_column_null_constraint_sql(expression) 766 return f"MODIFY COLUMN {this} {dtype}{null_constraint}" 767 768 def _prefixed_sql(self, prefix: str, expression: exp.Expr, arg: str) -> str: 769 sql = self.sql(expression, arg) 770 return f" {prefix} {sql}" if sql else "" 771 772 def _oldstyle_limit_sql(self, expression: exp.Show) -> str: 773 limit = self.sql(expression, "limit") 774 offset = self.sql(expression, "offset") 775 if limit: 776 limit_offset = f"{offset}, {limit}" if offset else limit 777 return f" LIMIT {limit_offset}" 778 return "" 779 780 def timestamptrunc_sql(self, expression: exp.TimestampTrunc) -> str: 781 unit = expression.args.get("unit") 782 if isinstance(unit, exp.WeekStart): 783 unit = exp.var(self.weekstart_name(unit)) 784 785 # Pick an old-enough date to avoid negative timestamp diffs 786 start_ts = "'0000-01-01 00:00:00'" 787 788 # Source: https://stackoverflow.com/a/32955740 789 timestamp_diff = build_date_delta(exp.TimestampDiff)([unit, start_ts, expression.this]) 790 interval = exp.Interval(this=timestamp_diff, unit=unit) 791 dateadd = build_date_delta_with_interval(exp.DateAdd)([start_ts, interval]) 792 793 return self.sql(dateadd) 794 795 def converttimezone_sql(self, expression: exp.ConvertTimezone) -> str: 796 from_tz = expression.args.get("source_tz") 797 to_tz = expression.args.get("target_tz") 798 dt = expression.args.get("timestamp") 799 800 return self.func("CONVERT_TZ", dt, from_tz, to_tz) 801 802 def attimezone_sql(self, expression: exp.AtTimeZone) -> str: 803 self.unsupported("AT TIME ZONE is not supported by MySQL") 804 return self.sql(expression.this) 805 806 def isascii_sql(self, expression: exp.IsAscii) -> str: 807 return f"REGEXP_LIKE({self.sql(expression.this)}, '^[[:ascii:]]*$')" 808 809 def ignorenulls_sql(self, expression: exp.IgnoreNulls) -> str: 810 # https://dev.mysql.com/doc/refman/8.4/en/window-function-descriptions.html 811 self.unsupported("MySQL does not support IGNORE NULLS.") 812 return self.sql(expression.this) 813 814 @unsupported_args("this") 815 def currentschema_sql(self, expression: exp.CurrentSchema) -> str: 816 return self.func("SCHEMA") 817 818 def partition_sql(self, expression: exp.Partition) -> str: 819 parent = expression.parent 820 if isinstance(parent, (exp.PartitionByRangeProperty, exp.PartitionByListProperty)): 821 return self.expressions(expression, flat=True) 822 return super().partition_sql(expression) 823 824 def _partition_by_sql( 825 self, expression: exp.PartitionByRangeProperty | exp.PartitionByListProperty, kind: str 826 ) -> str: 827 partitions = self.expressions(expression, key="partition_expressions", flat=True) 828 create = self.expressions(expression, key="create_expressions", flat=True) 829 return f"PARTITION BY {kind} ({partitions}) ({create})" 830 831 def partitionbyrangeproperty_sql(self, expression: exp.PartitionByRangeProperty) -> str: 832 return self._partition_by_sql(expression, "RANGE") 833 834 def partitionbylistproperty_sql(self, expression: exp.PartitionByListProperty) -> str: 835 return self._partition_by_sql(expression, "LIST") 836 837 def partitionlist_sql(self, expression: exp.PartitionList) -> str: 838 name = self.sql(expression, "this") 839 values = self.expressions(expression, flat=True) 840 return f"PARTITION {name} VALUES IN ({values})" 841 842 def partitionrange_sql(self, expression: exp.PartitionRange) -> str: 843 name = self.sql(expression, "this") 844 values = self.expressions(expression, flat=True) 845 return f"PARTITION {name} VALUES LESS THAN ({values})"
def
date_add_sql( kind: str) -> Callable[[sqlglot.generator.Generator, sqlglot.expressions.core.Expr], str]:
82def date_add_sql( 83 kind: str, 84) -> t.Callable[[generator.Generator, exp.Expr], str]: 85 def func(self: generator.Generator, expression: exp.Expr) -> str: 86 return self.func( 87 f"DATE_{kind}", 88 expression.this, 89 exp.Interval(this=expression.expression, unit=unit_to_var(expression)), 90 ) 91 92 return func
113class MySQLGenerator(generator.Generator): 114 SELECT_KINDS: tuple[str, ...] = () 115 TRY_SUPPORTED = False 116 SUPPORTS_UESCAPE = False 117 SUPPORTS_DECODE_CASE = False 118 SUPPORTS_MODIFY_COLUMN = True 119 SUPPORTS_CHANGE_COLUMN = True 120 SUPPORTS_ALTER_COLUMN_NULLABILITY = True 121 122 AFTER_HAVING_MODIFIER_TRANSFORMS = generator.AFTER_HAVING_MODIFIER_TRANSFORMS 123 124 INTERVAL_ALLOWS_PLURAL_FORM = False 125 LOCKING_READS_SUPPORTED = True 126 NULL_ORDERING_SUPPORTED: bool | None = None 127 JOIN_HINTS = False 128 TABLE_HINTS = True 129 DUPLICATE_KEY_UPDATE_WITH_SET = False 130 QUERY_HINT_SEP = " " 131 VALUES_AS_TABLE = False 132 NVL2_SUPPORTED = False 133 LAST_DAY_SUPPORTS_DATE_PART = False 134 JSON_TYPE_REQUIRED_FOR_EXTRACTION = True 135 JSON_PATH_BRACKETED_KEY_SUPPORTED = False 136 JSON_KEY_VALUE_PAIR_SEP = "," 137 SUPPORTS_TO_NUMBER = False 138 PARSE_JSON_NAME: str | None = None 139 PAD_FILL_PATTERN_IS_REQUIRED = True 140 WRAP_DERIVED_VALUES = False 141 VARCHAR_REQUIRES_SIZE = True 142 SUPPORTS_MEDIAN = False 143 UPDATE_STATEMENT_SUPPORTS_FROM = False 144 145 TRANSFORMS = { 146 **generator.Generator.TRANSFORMS, 147 exp.ArrayAgg: rename_func("GROUP_CONCAT"), 148 exp.BitwiseAndAgg: rename_func("BIT_AND"), 149 exp.BitwiseOrAgg: rename_func("BIT_OR"), 150 exp.BitwiseXorAgg: rename_func("BIT_XOR"), 151 exp.BitwiseCount: rename_func("BIT_COUNT"), 152 exp.Chr: lambda self, e: self.chr_sql(e, "CHAR"), 153 exp.CurrentDate: no_paren_current_date_sql, 154 exp.CurrentVersion: rename_func("VERSION"), 155 exp.DateDiff: remove_ts_or_ds_to_date( 156 lambda self, e: self.func("DATEDIFF", e.this, e.expression), ("this", "expression") 157 ), 158 exp.DateAdd: date_add_sql("ADD"), 159 exp.DateStrToDate: datestrtodate_sql, 160 exp.DateSub: date_add_sql("SUB"), 161 exp.DateTrunc: _date_trunc_sql, 162 exp.Day: remove_ts_or_ds_to_date(), 163 exp.DayOfMonth: remove_ts_or_ds_to_date(rename_func("DAYOFMONTH")), 164 exp.DayOfWeek: remove_ts_or_ds_to_date(rename_func("DAYOFWEEK")), 165 exp.DayOfYear: remove_ts_or_ds_to_date(rename_func("DAYOFYEAR")), 166 exp.GroupConcat: lambda self, e: ( 167 f"""GROUP_CONCAT({self.sql(e, "this")} SEPARATOR {self.sql(e, "separator") or "','"})""" 168 ), 169 exp.ILike: no_ilike_sql, 170 # https://dev.mysql.com/doc/refman/9.7/en/flow-control-functions.html#function_if 171 exp.If: if_sql(false_value="NULL"), 172 exp.JSONExtractScalar: arrow_json_extract_sql, 173 exp.Length: length_or_char_length_sql, 174 exp.LogicalOr: rename_func("MAX"), 175 exp.LogicalAnd: rename_func("MIN"), 176 exp.Max: max_or_greatest, 177 exp.Min: min_or_least, 178 exp.Month: remove_ts_or_ds_to_date(), 179 exp.NullSafeEQ: lambda self, e: self.binary(e, "<=>"), 180 exp.NullSafeNEQ: lambda self, e: f"NOT {self.binary(e, '<=>')}", 181 exp.NumberToStr: rename_func("FORMAT"), 182 exp.Pivot: no_pivot_sql, 183 exp.Select: transforms.preprocess( 184 [ 185 transforms.eliminate_distinct_on, 186 transforms.eliminate_semi_and_anti_joins, 187 transforms.eliminate_qualify, 188 transforms.eliminate_full_outer_join, 189 transforms.unnest_generate_date_array_using_recursive_cte, 190 ] 191 ), 192 exp.StrPosition: lambda self, e: strposition_sql( 193 self, e, func_name="LOCATE", supports_position=True 194 ), 195 exp.StrToDate: _str_to_date_sql, 196 exp.StrToTime: _str_to_date_sql, 197 exp.Stuff: rename_func("INSERT"), 198 exp.SessionUser: lambda *_: "SESSION_USER()", 199 exp.TableSample: no_tablesample_sql, 200 exp.TimeFromParts: rename_func("MAKETIME"), 201 exp.TimestampAdd: date_add_interval_sql("DATE", "ADD"), 202 exp.TimestampDiff: lambda self, e: self.func( 203 "TIMESTAMPDIFF", unit_to_var(e), e.expression, e.this 204 ), 205 exp.TimestampSub: date_add_interval_sql("DATE", "SUB"), 206 exp.TimeStrToUnix: rename_func("UNIX_TIMESTAMP"), 207 exp.TimeStrToTime: lambda self, e: timestrtotime_sql( 208 self, 209 e, 210 include_precision=not e.args.get("zone"), 211 ), 212 exp.TimeToStr: remove_ts_or_ds_to_date( 213 lambda self, e: self.func("DATE_FORMAT", e.this, self.format_time(e)) 214 ), 215 exp.Trim: trim_sql, 216 exp.Trunc: rename_func("TRUNCATE"), 217 exp.TryCast: no_trycast_sql, 218 exp.TsOrDsAdd: date_add_sql("ADD"), 219 exp.TsOrDsDiff: lambda self, e: self.func("DATEDIFF", e.this, e.expression), 220 exp.TsOrDsToDate: _ts_or_ds_to_date_sql, 221 exp.Unicode: lambda self, e: f"ORD(CONVERT({self.sql(e.this)} USING utf32))", 222 exp.UnixToTime: _unix_to_time_sql, 223 exp.Week: remove_ts_or_ds_to_date(), 224 exp.WeekOfYear: remove_ts_or_ds_to_date(rename_func("WEEKOFYEAR")), 225 exp.Year: remove_ts_or_ds_to_date(), 226 exp.UtcTimestamp: rename_func("UTC_TIMESTAMP"), 227 exp.UtcTime: rename_func("UTC_TIME"), 228 } 229 230 UNSIGNED_TYPE_MAPPING: t.ClassVar = { 231 exp.DType.UBIGINT: "BIGINT", 232 exp.DType.UINT: "INT", 233 exp.DType.UMEDIUMINT: "MEDIUMINT", 234 exp.DType.USMALLINT: "SMALLINT", 235 exp.DType.UTINYINT: "TINYINT", 236 exp.DType.UDECIMAL: "DECIMAL", 237 exp.DType.UDOUBLE: "DOUBLE", 238 } 239 240 TIMESTAMP_TYPE_MAPPING: t.ClassVar = { 241 exp.DType.DATETIME2: "DATETIME", 242 exp.DType.SMALLDATETIME: "DATETIME", 243 exp.DType.TIMESTAMP: "DATETIME", 244 exp.DType.TIMESTAMPNTZ: "DATETIME", 245 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 246 exp.DType.TIMESTAMPLTZ: "TIMESTAMP", 247 } 248 249 TYPE_MAPPING: t.ClassVar = { 250 exp.DType.NCHAR: "CHAR", 251 exp.DType.NVARCHAR: "VARCHAR", 252 exp.DType.INET: "INET", 253 exp.DType.ROWVERSION: "VARBINARY", 254 exp.DType.UBIGINT: "BIGINT", 255 exp.DType.UINT: "INT", 256 exp.DType.UMEDIUMINT: "MEDIUMINT", 257 exp.DType.USMALLINT: "SMALLINT", 258 exp.DType.UTINYINT: "TINYINT", 259 exp.DType.UDECIMAL: "DECIMAL", 260 exp.DType.UDOUBLE: "DOUBLE", 261 exp.DType.DATETIME2: "DATETIME", 262 exp.DType.SMALLDATETIME: "DATETIME", 263 exp.DType.TIMESTAMP: "DATETIME", 264 exp.DType.TIMESTAMPNTZ: "DATETIME", 265 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 266 exp.DType.TIMESTAMPLTZ: "TIMESTAMP", 267 } 268 269 PROPERTIES_LOCATION: t.ClassVar = { 270 **generator.Generator.PROPERTIES_LOCATION, 271 exp.TransientProperty: exp.Properties.Location.UNSUPPORTED, 272 exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED, 273 exp.PartitionedByProperty: exp.Properties.Location.UNSUPPORTED, 274 exp.PartitionByRangeProperty: exp.Properties.Location.POST_SCHEMA, 275 exp.PartitionByListProperty: exp.Properties.Location.POST_SCHEMA, 276 } 277 278 LIMIT_FETCH = "LIMIT" 279 280 LIMIT_ONLY_LITERALS = True 281 282 CHAR_CAST_MAPPING: t.ClassVar = dict.fromkeys( 283 ( 284 exp.DType.LONGTEXT, 285 exp.DType.LONGBLOB, 286 exp.DType.MEDIUMBLOB, 287 exp.DType.MEDIUMTEXT, 288 exp.DType.TEXT, 289 exp.DType.TINYBLOB, 290 exp.DType.TINYTEXT, 291 exp.DType.VARCHAR, 292 ), 293 "CHAR", 294 ) 295 SIGNED_CAST_MAPPING: t.ClassVar = dict.fromkeys( 296 ( 297 exp.DType.BIGINT, 298 exp.DType.BOOLEAN, 299 exp.DType.INT, 300 exp.DType.SMALLINT, 301 exp.DType.TINYINT, 302 exp.DType.MEDIUMINT, 303 ), 304 "SIGNED", 305 ) 306 307 # MySQL doesn't support many datatypes in cast. 308 # https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html#function_cast 309 CAST_MAPPING: t.ClassVar = { 310 exp.DType.LONGTEXT: "CHAR", 311 exp.DType.LONGBLOB: "CHAR", 312 exp.DType.MEDIUMBLOB: "CHAR", 313 exp.DType.MEDIUMTEXT: "CHAR", 314 exp.DType.TEXT: "CHAR", 315 exp.DType.TINYBLOB: "CHAR", 316 exp.DType.TINYTEXT: "CHAR", 317 exp.DType.VARCHAR: "CHAR", 318 exp.DType.BIGINT: "SIGNED", 319 exp.DType.BOOLEAN: "SIGNED", 320 exp.DType.INT: "SIGNED", 321 exp.DType.SMALLINT: "SIGNED", 322 exp.DType.TINYINT: "SIGNED", 323 exp.DType.MEDIUMINT: "SIGNED", 324 exp.DType.UBIGINT: "UNSIGNED", 325 } 326 327 TIMESTAMP_FUNC_TYPES: t.ClassVar = { 328 exp.DType.TIMESTAMPTZ, 329 exp.DType.TIMESTAMPLTZ, 330 } 331 332 # https://dev.mysql.com/doc/refman/8.0/en/keywords.html 333 RESERVED_KEYWORDS = { 334 "accessible", 335 "add", 336 "all", 337 "alter", 338 "analyze", 339 "and", 340 "as", 341 "asc", 342 "asensitive", 343 "before", 344 "between", 345 "bigint", 346 "binary", 347 "blob", 348 "both", 349 "by", 350 "call", 351 "cascade", 352 "case", 353 "change", 354 "char", 355 "character", 356 "check", 357 "collate", 358 "column", 359 "condition", 360 "constraint", 361 "continue", 362 "convert", 363 "create", 364 "cross", 365 "cube", 366 "cume_dist", 367 "current_date", 368 "current_time", 369 "current_timestamp", 370 "current_user", 371 "cursor", 372 "database", 373 "databases", 374 "day_hour", 375 "day_microsecond", 376 "day_minute", 377 "day_second", 378 "dec", 379 "decimal", 380 "declare", 381 "default", 382 "delayed", 383 "delete", 384 "dense_rank", 385 "desc", 386 "describe", 387 "deterministic", 388 "distinct", 389 "distinctrow", 390 "div", 391 "double", 392 "drop", 393 "dual", 394 "each", 395 "else", 396 "elseif", 397 "empty", 398 "enclosed", 399 "escaped", 400 "except", 401 "exists", 402 "exit", 403 "explain", 404 "false", 405 "fetch", 406 "first_value", 407 "float", 408 "float4", 409 "float8", 410 "for", 411 "force", 412 "foreign", 413 "from", 414 "fulltext", 415 "function", 416 "generated", 417 "get", 418 "grant", 419 "group", 420 "grouping", 421 "groups", 422 "having", 423 "high_priority", 424 "hour_microsecond", 425 "hour_minute", 426 "hour_second", 427 "if", 428 "ignore", 429 "in", 430 "index", 431 "infile", 432 "inner", 433 "inout", 434 "insensitive", 435 "insert", 436 "int", 437 "int1", 438 "int2", 439 "int3", 440 "int4", 441 "int8", 442 "integer", 443 "intersect", 444 "interval", 445 "into", 446 "io_after_gtids", 447 "io_before_gtids", 448 "is", 449 "iterate", 450 "join", 451 "json_table", 452 "key", 453 "keys", 454 "kill", 455 "lag", 456 "last_value", 457 "lateral", 458 "lead", 459 "leading", 460 "leave", 461 "left", 462 "like", 463 "limit", 464 "linear", 465 "lines", 466 "load", 467 "localtime", 468 "localtimestamp", 469 "lock", 470 "long", 471 "longblob", 472 "longtext", 473 "loop", 474 "low_priority", 475 "master_bind", 476 "master_ssl_verify_server_cert", 477 "match", 478 "maxvalue", 479 "mediumblob", 480 "mediumint", 481 "mediumtext", 482 "middleint", 483 "minute_microsecond", 484 "minute_second", 485 "mod", 486 "modifies", 487 "natural", 488 "not", 489 "no_write_to_binlog", 490 "nth_value", 491 "ntile", 492 "null", 493 "numeric", 494 "of", 495 "on", 496 "optimize", 497 "optimizer_costs", 498 "option", 499 "optionally", 500 "or", 501 "order", 502 "out", 503 "outer", 504 "outfile", 505 "over", 506 "partition", 507 "percent_rank", 508 "precision", 509 "primary", 510 "procedure", 511 "purge", 512 "range", 513 "rank", 514 "read", 515 "reads", 516 "read_write", 517 "real", 518 "recursive", 519 "references", 520 "regexp", 521 "release", 522 "rename", 523 "repeat", 524 "replace", 525 "require", 526 "resignal", 527 "restrict", 528 "return", 529 "revoke", 530 "right", 531 "rlike", 532 "row", 533 "rows", 534 "row_number", 535 "schema", 536 "schemas", 537 "second_microsecond", 538 "select", 539 "sensitive", 540 "separator", 541 "set", 542 "show", 543 "signal", 544 "smallint", 545 "spatial", 546 "specific", 547 "sql", 548 "sqlexception", 549 "sqlstate", 550 "sqlwarning", 551 "sql_big_result", 552 "sql_calc_found_rows", 553 "sql_small_result", 554 "ssl", 555 "starting", 556 "stored", 557 "straight_join", 558 "system", 559 "table", 560 "terminated", 561 "then", 562 "tinyblob", 563 "tinyint", 564 "tinytext", 565 "to", 566 "trailing", 567 "trigger", 568 "true", 569 "undo", 570 "union", 571 "unique", 572 "unlock", 573 "unsigned", 574 "update", 575 "usage", 576 "use", 577 "using", 578 "utc_date", 579 "utc_time", 580 "utc_timestamp", 581 "values", 582 "varbinary", 583 "varchar", 584 "varcharacter", 585 "varying", 586 "virtual", 587 "when", 588 "where", 589 "while", 590 "window", 591 "with", 592 "write", 593 "xor", 594 "year_month", 595 "zerofill", 596 } 597 598 SQL_SECURITY_VIEW_LOCATION: t.ClassVar = exp.Properties.Location.POST_CREATE 599 600 def makeinterval_sql(self: MySQLGenerator, expression: exp.MakeInterval) -> str: 601 intervals: list[exp.Interval] = [] 602 for arg_key, value in expression.args.items(): 603 if value is None: 604 continue 605 606 if isinstance(value, exp.Kwarg): 607 unit_name = _MAKE_INTERVAL_UNIT_ALIASES.get( 608 value.this.name.lower(), value.this.name.lower() 609 ) 610 value = value.expression 611 else: 612 unit_name = arg_key 613 614 intervals.append(exp.Interval(this=value.copy(), unit=exp.var(unit_name.upper()))) 615 616 if not intervals: 617 return self.function_fallback_sql(expression) 618 619 parent = expression.parent 620 sep = " - " if isinstance(parent, exp.Sub) and parent.expression is expression else " + " 621 622 return sep.join(self.sql(interval) for interval in intervals) 623 624 def locate_properties(self, properties: exp.Properties) -> defaultdict: 625 locations = super().locate_properties(properties) 626 627 # MySQL puts SQL SECURITY before VIEW but after the schema for functions/procedures 628 if isinstance(create := properties.parent, exp.Create) and create.kind == "VIEW": 629 post_schema = locations[exp.Properties.Location.POST_SCHEMA] 630 for i, p in enumerate(post_schema): 631 if isinstance(p, exp.SqlSecurityProperty): 632 post_schema.pop(i) 633 locations[self.SQL_SECURITY_VIEW_LOCATION].append(p) 634 break 635 636 return locations 637 638 def computedcolumnconstraint_sql(self, expression: exp.ComputedColumnConstraint) -> str: 639 persisted = "STORED" if expression.args.get("persisted") else "VIRTUAL" 640 return f"GENERATED ALWAYS AS ({self.sql(expression.this.unnest())}) {persisted}" 641 642 def array_sql(self, expression: exp.Array) -> str: 643 self.unsupported("Arrays are not supported by MySQL") 644 return self.function_fallback_sql(expression) 645 646 def arraycontainsall_sql(self, expression: exp.ArrayContainsAll) -> str: 647 self.unsupported("Array operations are not supported by MySQL") 648 return self.function_fallback_sql(expression) 649 650 def arraycontainedby_sql(self, expression: exp.ArrayContainedBy) -> str: 651 self.unsupported("Array operations are not supported by MySQL") 652 return self.function_fallback_sql(expression) 653 654 def dpipe_sql(self, expression: exp.DPipe) -> str: 655 return self.func("CONCAT", *expression.flatten()) 656 657 def extract_sql(self, expression: exp.Extract) -> str: 658 unit = expression.name 659 if unit and unit.lower() == "epoch": 660 return self.func("UNIX_TIMESTAMP", expression.expression) 661 662 return super().extract_sql(expression) 663 664 def datatype_sql(self, expression: exp.DataType) -> str: 665 if ( 666 self.VARCHAR_REQUIRES_SIZE 667 and expression.is_type(exp.DType.VARCHAR) 668 and not expression.expressions 669 ): 670 # `VARCHAR` must always have a size - if it doesn't, we always generate `TEXT` 671 return "TEXT" 672 673 # https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html 674 result = super().datatype_sql(expression) 675 if expression.this in self.UNSIGNED_TYPE_MAPPING: 676 result = f"{result} UNSIGNED" 677 678 return result 679 680 def jsonarraycontains_sql(self, expression: exp.JSONArrayContains) -> str: 681 return f"{self.sql(expression, 'this')} MEMBER OF({self.sql(expression, 'expression')})" 682 683 def cast_sql(self, expression: exp.Cast, safe_prefix: str | None = None) -> str: 684 if expression.to.this in self.TIMESTAMP_FUNC_TYPES: 685 return self.func("TIMESTAMP", expression.this) 686 687 to = self.CAST_MAPPING.get(expression.to.this) 688 689 if to: 690 expression.to.set("this", to) 691 return super().cast_sql(expression) 692 693 def show_sql(self, expression: exp.Show) -> str: 694 this = f" {expression.name}" 695 full = " FULL" if expression.args.get("full") else "" 696 global_ = " GLOBAL" if expression.args.get("global_") else "" 697 698 target = self.sql(expression, "target") 699 700 # SHOW CREATE ... takes a possibly qualified name, it has no FROM clause 701 # https://dev.mysql.com/doc/refman/8.4/en/show-create-table.html 702 if expression.name.startswith("CREATE") and (db_id := self.sql(expression, "db")): 703 target = f"{db_id}.{target}" 704 db = "" 705 else: 706 db = self._prefixed_sql("FROM", expression, "db") 707 708 target = f" {target}" if target else "" 709 if expression.name in ("COLUMNS", "INDEX"): 710 target = f" FROM{target}" 711 elif expression.name == "GRANTS": 712 target = f" FOR{target}" 713 elif expression.name in ("LINKS", "PARTITIONS"): 714 target = f" ON{target}" if target else "" 715 elif expression.name == "PROJECTIONS": 716 target = f" ON TABLE{target}" if target else "" 717 718 like = self._prefixed_sql("LIKE", expression, "like") 719 where = self.sql(expression, "where") 720 721 types = self.expressions(expression, key="types") 722 types = f" {types}" if types else types 723 query = self._prefixed_sql("FOR QUERY", expression, "query") 724 725 if expression.name == "PROFILE": 726 offset = self._prefixed_sql("OFFSET", expression, "offset") 727 limit = self._prefixed_sql("LIMIT", expression, "limit") 728 else: 729 offset = "" 730 limit = self._oldstyle_limit_sql(expression) 731 732 log = self._prefixed_sql("IN", expression, "log") 733 position = self._prefixed_sql("FROM", expression, "position") 734 735 channel = self._prefixed_sql("FOR CHANNEL", expression, "channel") 736 737 if expression.name == "ENGINE": 738 mutex_or_status = " MUTEX" if expression.args.get("mutex") else " STATUS" 739 else: 740 mutex_or_status = "" 741 742 for_table = self._prefixed_sql("FOR TABLE", expression, "for_table") 743 for_group = self._prefixed_sql("FOR GROUP", expression, "for_group") 744 for_user = self._prefixed_sql("FOR USER", expression, "for_user") 745 for_role = self._prefixed_sql("FOR ROLE", expression, "for_role") 746 into_outfile = self._prefixed_sql("INTO OUTFILE", expression, "into_outfile") 747 json = " JSON" if expression.args.get("json") else "" 748 749 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}" 750 751 def alterrename_sql(self, expression: exp.AlterRename, include_to: bool = True) -> str: 752 """To avoid TO keyword in ALTER ... RENAME statements. 753 It's moved from Doris, because it's the same for all MySQL, Doris, and StarRocks. 754 """ 755 return super().alterrename_sql(expression, include_to=False) 756 757 def altercolumn_sql(self, expression: exp.AlterColumn) -> str: 758 dtype = self.sql(expression, "dtype") 759 if not dtype: 760 return super().altercolumn_sql(expression) 761 762 if expression.args.get("exists"): 763 self.unsupported("ALTER COLUMN IF EXISTS is not supported by this dialect") 764 765 this = self.sql(expression, "this") 766 null_constraint = self._alter_column_null_constraint_sql(expression) 767 return f"MODIFY COLUMN {this} {dtype}{null_constraint}" 768 769 def _prefixed_sql(self, prefix: str, expression: exp.Expr, arg: str) -> str: 770 sql = self.sql(expression, arg) 771 return f" {prefix} {sql}" if sql else "" 772 773 def _oldstyle_limit_sql(self, expression: exp.Show) -> str: 774 limit = self.sql(expression, "limit") 775 offset = self.sql(expression, "offset") 776 if limit: 777 limit_offset = f"{offset}, {limit}" if offset else limit 778 return f" LIMIT {limit_offset}" 779 return "" 780 781 def timestamptrunc_sql(self, expression: exp.TimestampTrunc) -> str: 782 unit = expression.args.get("unit") 783 if isinstance(unit, exp.WeekStart): 784 unit = exp.var(self.weekstart_name(unit)) 785 786 # Pick an old-enough date to avoid negative timestamp diffs 787 start_ts = "'0000-01-01 00:00:00'" 788 789 # Source: https://stackoverflow.com/a/32955740 790 timestamp_diff = build_date_delta(exp.TimestampDiff)([unit, start_ts, expression.this]) 791 interval = exp.Interval(this=timestamp_diff, unit=unit) 792 dateadd = build_date_delta_with_interval(exp.DateAdd)([start_ts, interval]) 793 794 return self.sql(dateadd) 795 796 def converttimezone_sql(self, expression: exp.ConvertTimezone) -> str: 797 from_tz = expression.args.get("source_tz") 798 to_tz = expression.args.get("target_tz") 799 dt = expression.args.get("timestamp") 800 801 return self.func("CONVERT_TZ", dt, from_tz, to_tz) 802 803 def attimezone_sql(self, expression: exp.AtTimeZone) -> str: 804 self.unsupported("AT TIME ZONE is not supported by MySQL") 805 return self.sql(expression.this) 806 807 def isascii_sql(self, expression: exp.IsAscii) -> str: 808 return f"REGEXP_LIKE({self.sql(expression.this)}, '^[[:ascii:]]*$')" 809 810 def ignorenulls_sql(self, expression: exp.IgnoreNulls) -> str: 811 # https://dev.mysql.com/doc/refman/8.4/en/window-function-descriptions.html 812 self.unsupported("MySQL does not support IGNORE NULLS.") 813 return self.sql(expression.this) 814 815 @unsupported_args("this") 816 def currentschema_sql(self, expression: exp.CurrentSchema) -> str: 817 return self.func("SCHEMA") 818 819 def partition_sql(self, expression: exp.Partition) -> str: 820 parent = expression.parent 821 if isinstance(parent, (exp.PartitionByRangeProperty, exp.PartitionByListProperty)): 822 return self.expressions(expression, flat=True) 823 return super().partition_sql(expression) 824 825 def _partition_by_sql( 826 self, expression: exp.PartitionByRangeProperty | exp.PartitionByListProperty, kind: str 827 ) -> str: 828 partitions = self.expressions(expression, key="partition_expressions", flat=True) 829 create = self.expressions(expression, key="create_expressions", flat=True) 830 return f"PARTITION BY {kind} ({partitions}) ({create})" 831 832 def partitionbyrangeproperty_sql(self, expression: exp.PartitionByRangeProperty) -> str: 833 return self._partition_by_sql(expression, "RANGE") 834 835 def partitionbylistproperty_sql(self, expression: exp.PartitionByListProperty) -> str: 836 return self._partition_by_sql(expression, "LIST") 837 838 def partitionlist_sql(self, expression: exp.PartitionList) -> str: 839 name = self.sql(expression, "this") 840 values = self.expressions(expression, flat=True) 841 return f"PARTITION {name} VALUES IN ({values})" 842 843 def partitionrange_sql(self, expression: exp.PartitionRange) -> str: 844 name = self.sql(expression, "this") 845 values = self.expressions(expression, flat=True) 846 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.ArrayContainedBy'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.ArrayContainsAll'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.ArrayOverlaps'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.AssumeColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.AutoRefreshProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.BackupProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.BinaryColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CaseSpecificColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CalledOnNullInputProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.math.Ceil'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CharacterSetColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CharacterSetProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.ClusteredColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CollateColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CommentColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.ConnectByRoot'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.string.ConvertToCharset'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CopyGrantsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CredentialsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.CurrentCatalog'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.SessionUser'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.constraints.DateFormatColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.DefaultColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ApiProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ApplicationProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CatalogProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ComputeProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.DatabaseProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.DynamicProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.EmptyProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.EncodeColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.EndStatement'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.EnviromentProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.HandlerProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ParameterStyleProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.EphemeralColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.ExcludeColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ExecuteAsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Except'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ExternalProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.math.Floor'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Get'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.GlobalProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.HeapProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.HybridProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.IcebergProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.InheritsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.InlineLengthColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.InputModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Intersect'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.datatypes.IntervalSpan'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.Int64'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONBContainsAnyTopKeys'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONBContainsAllTopKeys'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONBContainsTopKey'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONBDeleteAtPath'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONBPathExists'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONObject'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONObjectAgg'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.LanguageProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.LocationProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.LogProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.MaskingProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.MaterializedProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.NetFunc'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.NetworkProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.NonClusteredColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.NoPrimaryIndexProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.NotForReplicationColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.OnCommitProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.OnProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.OnUpdateColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.Operator'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.OutputModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.ExtendsLeft'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.ExtendsRight'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.PathColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.PartitionedByBucket'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.PartitionByTruncate'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.PivotAny'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.PositionalColumn'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.ProjectionPolicyColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.InvisibleColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.ZeroFillColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Put'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.RemoteWithConnectionModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ReturnsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.RowAccessProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.SafeFunc'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SampleProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SecureProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SecurityIntegrationProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SetConfigProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SetProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SettingsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SharingProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SqlReadWriteProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SqlSecurityProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.StabilityProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Stream'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.StreamingTableProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.StrictProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ddl.SwapTable'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.TableColumn'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.Tags'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.TemporaryProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.TitleColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.ToMap'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ToTableProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.TransformModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.TransientProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.VirtualProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ddl.TriggerExecute'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Union'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.UnloggedProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.UsingTemplateProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.UsingData'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.UppercaseColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.temporal.UtcDate'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.temporal.UtcTime'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.UtcTimestamp'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.query.Variadic'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.VarMap'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ViewAttributeProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.VolatileProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.WithJournalTableProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.WithProcedureOptions'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.WithSchemaBindingProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.WithOperator'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ForceProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.aggregate.ArrayAgg'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.math.BitwiseAndAgg'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.math.BitwiseOrAgg'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.math.BitwiseXorAgg'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.math.BitwiseCount'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.string.Chr'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.CurrentDate'>: <function no_paren_current_date_sql>, <class 'sqlglot.expressions.functions.CurrentVersion'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.DateDiff'>: <function remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.temporal.DateAdd'>: <function date_add_sql.<locals>.func>, <class 'sqlglot.expressions.temporal.DateStrToDate'>: <function datestrtodate_sql>, <class 'sqlglot.expressions.temporal.DateSub'>: <function date_add_sql.<locals>.func>, <class 'sqlglot.expressions.temporal.DateTrunc'>: <function _date_trunc_sql>, <class 'sqlglot.expressions.temporal.Day'>: <function remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.temporal.DayOfMonth'>: <function remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.temporal.DayOfWeek'>: <function remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.temporal.DayOfYear'>: <function remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.aggregate.GroupConcat'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.core.ILike'>: <function no_ilike_sql>, <class 'sqlglot.expressions.functions.If'>: <function if_sql.<locals>._if_sql>, <class 'sqlglot.expressions.json.JSONExtractScalar'>: <function arrow_json_extract_sql>, <class 'sqlglot.expressions.string.Length'>: <function length_or_char_length_sql>, <class 'sqlglot.expressions.aggregate.LogicalOr'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.aggregate.LogicalAnd'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.aggregate.Max'>: <function max_or_greatest>, <class 'sqlglot.expressions.aggregate.Min'>: <function min_or_least>, <class 'sqlglot.expressions.temporal.Month'>: <function remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.core.NullSafeEQ'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.core.NullSafeNEQ'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.string.NumberToStr'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.query.Pivot'>: <function no_pivot_sql>, <class 'sqlglot.expressions.query.Select'>: <function preprocess.<locals>._to_sql>, <class 'sqlglot.expressions.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: ClassVar =
{<DType.UBIGINT: 'UBIGINT'>: 'BIGINT', <DType.UINT: 'UINT'>: 'INT', <DType.UMEDIUMINT: 'UMEDIUMINT'>: 'MEDIUMINT', <DType.USMALLINT: 'USMALLINT'>: 'SMALLINT', <DType.UTINYINT: 'UTINYINT'>: 'TINYINT', <DType.UDECIMAL: 'UDECIMAL'>: 'DECIMAL', <DType.UDOUBLE: 'UDOUBLE'>: 'DOUBLE'}
TIMESTAMP_TYPE_MAPPING: ClassVar =
{<DType.DATETIME2: 'DATETIME2'>: 'DATETIME', <DType.SMALLDATETIME: 'SMALLDATETIME'>: 'DATETIME', <DType.TIMESTAMP: 'TIMESTAMP'>: 'DATETIME', <DType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>: 'DATETIME', <DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>: 'TIMESTAMP', <DType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>: 'TIMESTAMP'}
TYPE_MAPPING: ClassVar =
{<DType.NCHAR: 'NCHAR'>: 'CHAR', <DType.NVARCHAR: 'NVARCHAR'>: 'VARCHAR', <DType.INET: 'INET'>: 'INET', <DType.ROWVERSION: 'ROWVERSION'>: 'VARBINARY', <DType.UBIGINT: 'UBIGINT'>: 'BIGINT', <DType.UINT: 'UINT'>: 'INT', <DType.UMEDIUMINT: 'UMEDIUMINT'>: 'MEDIUMINT', <DType.USMALLINT: 'USMALLINT'>: 'SMALLINT', <DType.UTINYINT: 'UTINYINT'>: 'TINYINT', <DType.UDECIMAL: 'UDECIMAL'>: 'DECIMAL', <DType.UDOUBLE: 'UDOUBLE'>: 'DOUBLE', <DType.DATETIME2: 'DATETIME2'>: 'DATETIME', <DType.SMALLDATETIME: 'SMALLDATETIME'>: 'DATETIME', <DType.TIMESTAMP: 'TIMESTAMP'>: 'DATETIME', <DType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>: 'DATETIME', <DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>: 'TIMESTAMP', <DType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>: 'TIMESTAMP'}
PROPERTIES_LOCATION: ClassVar =
{<class 'sqlglot.expressions.properties.AllowedValuesProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.AlgorithmProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.ApiProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.ApplicationProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.AutoIncrementProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.AutoRefreshProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.BackupProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.BlockCompressionProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.CalledOnNullInputProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.CatalogProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.CharacterSetProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ChecksumProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.CollateProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ComputeProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.CopyGrantsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.query.Cluster'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ClusteredByProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ClusterProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DistributedByProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DuplicateKeyProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DataBlocksizeProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.DatabaseProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.DataDeletionProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DefinerProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.DictRange'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DictProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DynamicProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.DistKeyProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DistStyleProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.EmptyProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.EncodeProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.EngineProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.EnviromentProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.HandlerProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ParameterStyleProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ExecuteAsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ExternalProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.FallbackProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.FileFormatProperty'>: <PropertiesLocation.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.properties.FreespaceProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.GlobalProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.HeapProperty'>: <PropertiesLocation.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.properties.HybridProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.InheritsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.IcebergProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.IncludeProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.InputModelProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.IsolatedLoadingProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.JournalProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.LanguageProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.LikeProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.LocationProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.LockProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.LockingProperty'>: <PropertiesLocation.POST_ALIAS: 'POST_ALIAS'>, <class 'sqlglot.expressions.properties.LogProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.MaskingProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.MaterializedProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.MergeBlockRatioProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.ModuleProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.NetworkProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.NoPrimaryIndexProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.OnProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.OnCommitProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.query.Order'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.OutputModelProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.PartitionedByProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.PartitionedOfProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.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: ClassVar =
{<DType.LONGTEXT: 'LONGTEXT'>: 'CHAR', <DType.LONGBLOB: 'LONGBLOB'>: 'CHAR', <DType.MEDIUMBLOB: 'MEDIUMBLOB'>: 'CHAR', <DType.MEDIUMTEXT: 'MEDIUMTEXT'>: 'CHAR', <DType.TEXT: 'TEXT'>: 'CHAR', <DType.TINYBLOB: 'TINYBLOB'>: 'CHAR', <DType.TINYTEXT: 'TINYTEXT'>: 'CHAR', <DType.VARCHAR: 'VARCHAR'>: 'CHAR', <DType.BIGINT: 'BIGINT'>: 'SIGNED', <DType.BOOLEAN: 'BOOLEAN'>: 'SIGNED', <DType.INT: 'INT'>: 'SIGNED', <DType.SMALLINT: 'SMALLINT'>: 'SIGNED', <DType.TINYINT: 'TINYINT'>: 'SIGNED', <DType.MEDIUMINT: 'MEDIUMINT'>: 'SIGNED', <DType.UBIGINT: 'UBIGINT'>: 'UNSIGNED'}
TIMESTAMP_FUNC_TYPES: ClassVar =
{<DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <DType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>}
RESERVED_KEYWORDS =
{'sql', 'asc', 'lag', 'from', 'option', 'utc_timestamp', 'sql_small_result', 'databases', 'real', 'asensitive', 'to', 'exists', 'int1', 'localtime', 'sql_big_result', 'using', 'delayed', 'infile', 'or', 'references', 'left', 'each', 'day_hour', 'trailing', 'purge', 'json_table', 'order', 'limit', 'cursor', 'join', 'smallint', 'separator', 'float4', 'no_write_to_binlog', 'index', 'elseif', 'procedure', 'set', 'int4', 'kill', 'primary', 'div', 'double', 'optionally', 'case', 'longtext', 'day_second', 'check', 'decimal', 'condition', 'outfile', 'character', 'mediumint', 'ssl', 'before', 'hour_minute', 'rank', 'sqlwarning', 'write', 'second_microsecond', 'group', 'release', 'mediumblob', 'alter', 'over', 'current_time', 'day_minute', 'create', 'tinyblob', 'row_number', 'hour_microsecond', 'get', 'select', 'modifies', 'undo', 'utc_time', 'fulltext', 'iterate', 'add', 'dense_rank', 'read', 'inout', 'last_value', 'in', 'convert', 'tinytext', 'outer', 'utc_date', 'rlike', 'xor', 'schema', 'replace', 'fetch', 'minute_second', 'call', 'change', 'unsigned', 'lines', 'blob', 'zerofill', 'explain', 'unlock', 'cross', 'current_date', 'while', 'long', 'is', 'true', 'union', 'column', 'optimizer_costs', 'on', 'all', 'int2', 'interval', 'reads', 'show', 'match', 'day_microsecond', 'drop', 'lateral', 'cube', 'analyze', 'int8', 'else', 'dec', 'varbinary', 'and', 'collate', 'escaped', 'current_timestamp', 'require', 'inner', 'first_value', 'integer', 'values', 'for', 'empty', 'spatial', 'delete', 'generated', 'except', 'recursive', 'where', 'rows', 'varcharacter', 'io_after_gtids', 'database', 'low_priority', 'if', 'unique', 'grouping', 'ntile', 'both', 'having', 'char', 'key', 'like', 'table', 'sqlstate', 'lead', 'trigger', 'mediumtext', 'numeric', 'desc', 'foreign', 'then', 'starting', 'optimize', 'not', 'deterministic', 'row', 'loop', 'grant', 'specific', 'float', 'terminated', 'enclosed', 'nth_value', 'usage', 'int', 'minute_microsecond', 'ignore', 'signal', 'window', 'varchar', 'keys', 'regexp', 'binary', 'virtual', 'partition', 'stored', 'middleint', 'localtimestamp', 'resignal', 'io_before_gtids', 'distinct', 'into', 'cascade', 'restrict', 'load', 'rename', 'right', 'force', 'groups', 'sqlexception', 'insert', 'between', 'describe', 'schemas', 'intersect', 'false', 'of', 'revoke', 'leave', 'float8', 'tinyint', 'update', 'master_ssl_verify_server_cert', 'sql_calc_found_rows', 'system', 'int3', 'dual', 'precision', 'use', 'when', 'insensitive', 'return', 'lock', 'varying', 'constraint', 'default', 'cume_dist', 'exit', 'linear', 'repeat', 'declare', 'current_user', 'accessible', 'mod', 'percent_rank', 'sensitive', 'high_priority', 'out', 'read_write', 'with', 'leading', 'distinctrow', 'master_bind', 'hour_second', 'year_month', 'by', 'longblob', 'as', 'null', 'natural', 'continue', 'bigint', 'range', 'function', 'straight_join', 'maxvalue'}
def
makeinterval_sql( self: MySQLGenerator, expression: sqlglot.expressions.temporal.MakeInterval) -> str:
600 def makeinterval_sql(self: MySQLGenerator, expression: exp.MakeInterval) -> str: 601 intervals: list[exp.Interval] = [] 602 for arg_key, value in expression.args.items(): 603 if value is None: 604 continue 605 606 if isinstance(value, exp.Kwarg): 607 unit_name = _MAKE_INTERVAL_UNIT_ALIASES.get( 608 value.this.name.lower(), value.this.name.lower() 609 ) 610 value = value.expression 611 else: 612 unit_name = arg_key 613 614 intervals.append(exp.Interval(this=value.copy(), unit=exp.var(unit_name.upper()))) 615 616 if not intervals: 617 return self.function_fallback_sql(expression) 618 619 parent = expression.parent 620 sep = " - " if isinstance(parent, exp.Sub) and parent.expression is expression else " + " 621 622 return sep.join(self.sql(interval) for interval in intervals)
def
locate_properties( self, properties: sqlglot.expressions.properties.Properties) -> collections.defaultdict:
624 def locate_properties(self, properties: exp.Properties) -> defaultdict: 625 locations = super().locate_properties(properties) 626 627 # MySQL puts SQL SECURITY before VIEW but after the schema for functions/procedures 628 if isinstance(create := properties.parent, exp.Create) and create.kind == "VIEW": 629 post_schema = locations[exp.Properties.Location.POST_SCHEMA] 630 for i, p in enumerate(post_schema): 631 if isinstance(p, exp.SqlSecurityProperty): 632 post_schema.pop(i) 633 locations[self.SQL_SECURITY_VIEW_LOCATION].append(p) 634 break 635 636 return locations
def
computedcolumnconstraint_sql( self, expression: sqlglot.expressions.constraints.ComputedColumnConstraint) -> str:
664 def datatype_sql(self, expression: exp.DataType) -> str: 665 if ( 666 self.VARCHAR_REQUIRES_SIZE 667 and expression.is_type(exp.DType.VARCHAR) 668 and not expression.expressions 669 ): 670 # `VARCHAR` must always have a size - if it doesn't, we always generate `TEXT` 671 return "TEXT" 672 673 # https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html 674 result = super().datatype_sql(expression) 675 if expression.this in self.UNSIGNED_TYPE_MAPPING: 676 result = f"{result} UNSIGNED" 677 678 return result
def
cast_sql( self, expression: sqlglot.expressions.functions.Cast, safe_prefix: str | None = None) -> str:
683 def cast_sql(self, expression: exp.Cast, safe_prefix: str | None = None) -> str: 684 if expression.to.this in self.TIMESTAMP_FUNC_TYPES: 685 return self.func("TIMESTAMP", expression.this) 686 687 to = self.CAST_MAPPING.get(expression.to.this) 688 689 if to: 690 expression.to.set("this", to) 691 return super().cast_sql(expression)
693 def show_sql(self, expression: exp.Show) -> str: 694 this = f" {expression.name}" 695 full = " FULL" if expression.args.get("full") else "" 696 global_ = " GLOBAL" if expression.args.get("global_") else "" 697 698 target = self.sql(expression, "target") 699 700 # SHOW CREATE ... takes a possibly qualified name, it has no FROM clause 701 # https://dev.mysql.com/doc/refman/8.4/en/show-create-table.html 702 if expression.name.startswith("CREATE") and (db_id := self.sql(expression, "db")): 703 target = f"{db_id}.{target}" 704 db = "" 705 else: 706 db = self._prefixed_sql("FROM", expression, "db") 707 708 target = f" {target}" if target else "" 709 if expression.name in ("COLUMNS", "INDEX"): 710 target = f" FROM{target}" 711 elif expression.name == "GRANTS": 712 target = f" FOR{target}" 713 elif expression.name in ("LINKS", "PARTITIONS"): 714 target = f" ON{target}" if target else "" 715 elif expression.name == "PROJECTIONS": 716 target = f" ON TABLE{target}" if target else "" 717 718 like = self._prefixed_sql("LIKE", expression, "like") 719 where = self.sql(expression, "where") 720 721 types = self.expressions(expression, key="types") 722 types = f" {types}" if types else types 723 query = self._prefixed_sql("FOR QUERY", expression, "query") 724 725 if expression.name == "PROFILE": 726 offset = self._prefixed_sql("OFFSET", expression, "offset") 727 limit = self._prefixed_sql("LIMIT", expression, "limit") 728 else: 729 offset = "" 730 limit = self._oldstyle_limit_sql(expression) 731 732 log = self._prefixed_sql("IN", expression, "log") 733 position = self._prefixed_sql("FROM", expression, "position") 734 735 channel = self._prefixed_sql("FOR CHANNEL", expression, "channel") 736 737 if expression.name == "ENGINE": 738 mutex_or_status = " MUTEX" if expression.args.get("mutex") else " STATUS" 739 else: 740 mutex_or_status = "" 741 742 for_table = self._prefixed_sql("FOR TABLE", expression, "for_table") 743 for_group = self._prefixed_sql("FOR GROUP", expression, "for_group") 744 for_user = self._prefixed_sql("FOR USER", expression, "for_user") 745 for_role = self._prefixed_sql("FOR ROLE", expression, "for_role") 746 into_outfile = self._prefixed_sql("INTO OUTFILE", expression, "into_outfile") 747 json = " JSON" if expression.args.get("json") else "" 748 749 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:
751 def alterrename_sql(self, expression: exp.AlterRename, include_to: bool = True) -> str: 752 """To avoid TO keyword in ALTER ... RENAME statements. 753 It's moved from Doris, because it's the same for all MySQL, Doris, and StarRocks. 754 """ 755 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.
757 def altercolumn_sql(self, expression: exp.AlterColumn) -> str: 758 dtype = self.sql(expression, "dtype") 759 if not dtype: 760 return super().altercolumn_sql(expression) 761 762 if expression.args.get("exists"): 763 self.unsupported("ALTER COLUMN IF EXISTS is not supported by this dialect") 764 765 this = self.sql(expression, "this") 766 null_constraint = self._alter_column_null_constraint_sql(expression) 767 return f"MODIFY COLUMN {this} {dtype}{null_constraint}"
781 def timestamptrunc_sql(self, expression: exp.TimestampTrunc) -> str: 782 unit = expression.args.get("unit") 783 if isinstance(unit, exp.WeekStart): 784 unit = exp.var(self.weekstart_name(unit)) 785 786 # Pick an old-enough date to avoid negative timestamp diffs 787 start_ts = "'0000-01-01 00:00:00'" 788 789 # Source: https://stackoverflow.com/a/32955740 790 timestamp_diff = build_date_delta(exp.TimestampDiff)([unit, start_ts, expression.this]) 791 interval = exp.Interval(this=timestamp_diff, unit=unit) 792 dateadd = build_date_delta_with_interval(exp.DateAdd)([start_ts, interval]) 793 794 return self.sql(dateadd)
@unsupported_args('this')
def
currentschema_sql(self, expression: sqlglot.expressions.functions.CurrentSchema) -> str:
def
partitionbyrangeproperty_sql( self, expression: sqlglot.expressions.properties.PartitionByRangeProperty) -> str:
def
partitionbylistproperty_sql( self, expression: sqlglot.expressions.properties.PartitionByListProperty) -> str:
Inherited Members
- sqlglot.generator.Generator
- Generator
- WINDOW_FUNCS_WITH_NULL_ORDERING
- IGNORE_NULLS_IN_FUNC
- IGNORE_NULLS_BEFORE_ORDER
- EXCEPT_INTERSECT_SUPPORT_ALL_CLAUSE
- CREATE_FUNCTION_RETURN_AS
- MATCHED_BY_SOURCE
- SUPPORTS_MERGE_WHERE
- SINGLE_STRING_INTERVAL
- AUTO_REFRESH_BARE_INTERVALS
- RENAME_TABLE_WITH_DB
- GROUPINGS_SEP
- SUPPORTS_GROUPING_SETS_AS_SUFFIX
- INDEX_ON
- INOUT_SEPARATOR
- DIRECTED_JOINS
- QUERY_HINTS
- IS_BOOL_ALLOWED
- LIMIT_IS_TOP
- RETURNING_END
- EXTRACT_ALLOWS_QUOTES
- TZ_TO_WITH_TIME_ZONE
- ALTER_TABLE_INCLUDE_COLUMN_KEYWORD
- UNNEST_WITH_ORDINALITY
- SEMI_ANTI_JOIN_WITH_SIDE
- COMPUTED_COLUMN_WITH_TYPE
- SUPPORTS_TABLE_COPY
- TABLESAMPLE_REQUIRES_PARENS
- TABLESAMPLE_SIZE_IS_ROWS
- TABLESAMPLE_KEYWORDS
- TABLESAMPLE_WITH_METHOD
- TABLESAMPLE_SEED_KEYWORD
- HISTORICAL_DATA_POST_ALIAS
- COLLATE_IS_FUNC
- DATA_TYPE_SPECIFIERS_ALLOWED
- ENSURE_BOOLS
- CTE_RECURSIVE_KEYWORD_REQUIRED
- SUPPORTS_SINGLE_ARG_CONCAT
- SUPPORTS_TABLE_ALIAS_COLUMNS
- SUPPORTS_NAMED_CTE_COLUMNS
- UNPIVOT_ALIASES_ARE_IDENTIFIERS
- PIVOT_ALIAS_WITH_AS
- INSERT_OVERWRITE
- SUPPORTS_SELECT_INTO
- SUPPORTS_UNLOGGED_TABLES
- SUPPORTS_CREATE_TABLE_LIKE
- SUPPORTS_ALTER_COLUMN_IF_EXISTS
- LIKE_PROPERTY_INSIDE_SCHEMA
- MULTI_ARG_DISTINCT
- JSON_PATH_SINGLE_QUOTE_ESCAPE
- JSON_PATH_KEY_QUOTED_FORCES_BRACKETS
- SUPPORTED_JSON_PATH_PARTS
- CAN_IMPLEMENT_ARRAY_ANY
- SUPPORTS_WINDOW_EXCLUDE
- SET_OP_MODIFIERS
- SET_OP_LIMITS
- SET_OP_PARENTHESIZED_OPERANDS
- COPY_PARAMS_ARE_WRAPPED
- COPY_PARAMS_EQ_REQUIRED
- COPY_HAS_INTO_KEYWORD
- UNICODE_SUBSTITUTE
- STAR_EXCEPT
- HEX_FUNC
- WITH_PROPERTIES_PREFIX
- QUOTE_JSON_PATH
- SUPPORTS_EXPLODING_PROJECTIONS
- ARRAY_CONCAT_IS_VAR_LEN
- SUPPORTS_CONVERT_TIMEZONE
- SUPPORTS_UNIX_SECONDS
- ALTER_SET_WRAPPED
- NORMALIZE_EXTRACT_DATE_PARTS
- ARRAY_SIZE_NAME
- ALTER_SET_TYPE
- ARRAY_SIZE_DIM_REQUIRED
- SUPPORTS_BETWEEN_FLAGS
- SUPPORTS_LIKE_QUANTIFIERS
- MATCH_AGAINST_TABLE_PREFIX
- SET_ASSIGNMENT_REQUIRES_VARIABLE_KEYWORD
- DECLARE_DEFAULT_ASSIGNMENT
- STAR_EXCLUDE_REQUIRES_DERIVED_TABLE
- SUPPORTS_DROP_ALTER_ICEBERG_PROPERTY
- UNSUPPORTED_TYPES
- TYPE_PARAM_SETTINGS
- TIME_PART_SINGULARS
- TOKEN_MAPPING
- STRUCT_DELIMITER
- PARAMETER_TOKEN
- NAMED_PLACEHOLDER_TOKEN
- EXPRESSION_PRECEDES_PROPERTIES_CREATABLES
- WITH_SEPARATED_COMMENTS
- EXCLUDE_COMMENTS
- UNWRAPPED_INTERVAL_VALUES
- PARAMETERIZABLE_TEXT_TYPES
- EXPRESSIONS_WITHOUT_NESTED_CTES
- RESPECT_IGNORE_NULLS_UNSUPPORTED_EXPRESSIONS
- MOD_OPERATOR
- MOD_PAREN_PARENT_TYPES
- SAFE_JSON_PATH_KEY_RE
- SENTINEL_LINE_BREAK
- pretty
- identify
- normalize
- pad
- unsupported_level
- max_unsupported
- leading_comma
- max_text_width
- comments
- dialect
- normalize_functions
- unsupported_messages
- generate
- preprocess
- unsupported
- sep
- seg
- sanitize_comment
- maybe_comment
- wrap
- no_identify
- normalize_func
- indent
- sql
- uncache_sql
- cache_sql
- characterset_sql
- column_parts
- column_sql
- pseudocolumn_sql
- columnposition_sql
- columndef_sql
- columnconstraint_sql
- autoincrementcolumnconstraint_sql
- compresscolumnconstraint_sql
- generatedasidentitycolumnconstraint_sql
- generatedasrowcolumnconstraint_sql
- periodforsystemtimeconstraint_sql
- notnullcolumnconstraint_sql
- primarykeycolumnconstraint_sql
- uniquecolumnconstraint_sql
- inoutcolumnconstraint_sql
- createable_sql
- create_sql
- sequenceproperties_sql
- triggerproperties_sql
- triggerreferencing_sql
- triggerevent_sql
- clone_sql
- describe_sql
- heredoc_sql
- prepend_ctes
- with_sql
- cte_sql
- tablealias_sql
- bitstring_sql
- hexstring_sql
- bytestring_sql
- unicodestring_sql
- rawstring_sql
- datatypeparam_sql
- datatype_param_bound_limiter
- directory_sql
- delete_sql
- drop_sql
- set_operation
- set_operations
- fetch_sql
- limitoptions_sql
- filter_sql
- hint_sql
- indexparameters_sql
- index_sql
- dynamicidentifier_sql
- identifier_sql
- hex_sql
- lowerhex_sql
- inputoutputformat_sql
- national_sql
- properties_sql
- root_properties
- properties
- with_properties
- property_name
- property_sql
- uuidproperty_sql
- likeproperty_sql
- fallbackproperty_sql
- journalproperty_sql
- freespaceproperty_sql
- checksumproperty_sql
- mergeblockratioproperty_sql
- moduleproperty_sql
- datablocksizeproperty_sql
- blockcompressionproperty_sql
- isolatedloadingproperty_sql
- partitionboundspec_sql
- partitionedofproperty_sql
- lockingproperty_sql
- withdataproperty_sql
- withsystemversioningproperty_sql
- insert_sql
- introducer_sql
- kill_sql
- pseudotype_sql
- objectidentifier_sql
- onconflict_sql
- returning_sql
- rowformatdelimitedproperty_sql
- withtablehint_sql
- indextablehint_sql
- historicaldata_sql
- table_parts
- table_sql
- tablefromrows_sql
- tablesample_sql
- pivot_sql
- version_sql
- tuple_sql
- update_sql
- values_sql
- var_sql
- into_sql
- from_sql
- groupingsets_sql
- rollup_sql
- rollupindex_sql
- rollupproperty_sql
- cube_sql
- group_sql
- having_sql
- connect_sql
- prior_sql
- join_sql
- lambda_sql
- lateral_op
- lateral_sql
- limit_sql
- offset_sql
- setitem_sql
- set_sql
- queryband_sql
- pragma_sql
- lock_sql
- literal_sql
- escape_str
- loaddata_sql
- null_sql
- boolean_sql
- booland_sql
- boolor_sql
- order_sql
- withfill_sql
- cluster_sql
- clusterproperty_sql
- distribute_sql
- sort_sql
- ordered_sql
- matchrecognizemeasure_sql
- matchrecognize_sql
- query_modifiers
- options_modifier
- forclause_sql
- queryoption_sql
- offset_limit_modifiers
- after_limit_modifiers
- select_sql
- schema_sql
- schema_columns_sql
- star_sql
- parameter_sql
- sessionparameter_sql
- placeholder_sql
- subquery_sql
- qualify_sql
- unnest_sql
- prewhere_sql
- where_sql
- window_sql
- partition_by_sql
- windowspec_sql
- withingroup_sql
- between_sql
- bracket_offset_expressions
- bracket_sql
- all_sql
- any_sql
- exists_sql
- case_sql
- constraint_sql
- nextvaluefor_sql
- trim_sql
- convert_concat_args
- concat_sql
- concatws_sql
- check_sql
- foreignkey_sql
- primarykey_sql
- timeserieskey_sql
- if_sql
- matchagainst_sql
- jsonkeyvalue_sql
- jsonpath_sql
- json_path_part
- formatjson_sql
- formatphrase_sql
- jsonarray_sql
- jsonarrayagg_sql
- jsoncolumndef_sql
- jsonschema_sql
- jsontable_sql
- openjsoncolumndef_sql
- openjson_sql
- in_sql
- in_unnest_op
- interval_sql
- return_sql
- reference_sql
- anonymous_sql
- paren_sql
- neg_sql
- not_sql
- alias_sql
- pivotalias_sql
- aliases_sql
- atindex_sql
- fromtimezone_sql
- fromiso8601date_sql
- fromiso8601timestamp_sql
- fromiso8601timestampnanos_sql
- add_sql
- and_sql
- or_sql
- xor_sql
- connector_sql
- bitwiseand_sql
- bitwiseleftshift_sql
- bitwisenot_sql
- bitwiseor_sql
- bitwiserightshift_sql
- bitwisexor_sql
- strtotime_sql
- strtodate_sql
- parsedatetime_sql
- currentdate_sql
- collate_sql
- command_sql
- comment_sql
- mergetreettlaction_sql
- mergetreettl_sql
- transaction_sql
- commit_sql
- rollback_sql
- modifycolumn_sql
- alterindex_sql
- alterdiststyle_sql
- altersortkey_sql
- renamecolumn_sql
- alterset_sql
- alter_sql
- altersession_sql
- add_column_sql
- droppartition_sql
- dropprimarykey_sql
- addconstraint_sql
- addpartition_sql
- distinct_sql
- respectnulls_sql
- havingmax_sql
- intdiv_sql
- div_sql
- safedivide_sql
- overlaps_sql
- distance_sql
- distancend_sql
- dot_sql
- eq_sql
- propertyeq_sql
- escape_sql
- glob_sql
- gt_sql
- gte_sql
- is_sql
- like_sql
- ilike_sql
- match_sql
- similarto_sql
- lt_sql
- lte_sql
- mod_sql
- mul_sql
- neq_sql
- nullsafeeq_sql
- nullsafeneq_sql
- sub_sql
- trycast_sql
- jsoncast_sql
- try_sql
- log_sql
- use_sql
- binary
- ceil_floor
- function_fallback_sql
- func
- format_args
- too_wide
- format_time
- expressions
- op_expressions
- naked_property
- tag_sql
- token_sql
- userdefinedfunction_sql
- macrooverloads_sql
- macrooverload_sql
- joinhint_sql
- kwarg_sql
- when_sql
- whens_sql
- merge_sql
- tochar_sql
- tonumber_sql
- dictproperty_sql
- dictrange_sql
- dictsubproperty_sql
- duplicatekeyproperty_sql
- uniquekeyproperty_sql
- distributedbyproperty_sql
- oncluster_sql
- clusteredbyproperty_sql
- anyvalue_sql
- querytransform_sql
- indexconstraintoption_sql
- checkcolumnconstraint_sql
- indexcolumnconstraint_sql
- nvl2_sql
- nthvalue_sql
- comprehension_sql
- columnprefix_sql
- opclass_sql
- predict_sql
- generateembedding_sql
- generatetext_sql
- generatetable_sql
- generatebool_sql
- generateint_sql
- generatedouble_sql
- mltranslate_sql
- mlforecast_sql
- aiforecast_sql
- featuresattime_sql
- vectorsearch_sql
- forin_sql
- refresh_sql
- toarray_sql
- tsordstotime_sql
- tsordstotimestamp_sql
- tsordstodatetime_sql
- tsordstodate_sql
- unixdate_sql
- lastday_sql
- dateadd_sql
- arrayinsert_sql
- arrayany_sql
- struct_sql
- truncatetable_sql
- convert_sql
- copyparameter_sql
- credentials_sql
- copy_sql
- semicolon_sql
- datadeletionproperty_sql
- maskingpolicycolumnconstraint_sql
- gapfill_sql
- scope_resolution
- scoperesolution_sql
- parsejson_sql
- rand_sql
- changes_sql
- pad_sql
- summarize_sql
- explodinggenerateseries_sql
- json_sql
- jsonvalue_sql
- skipjsoncolumn_sql
- conditionalinsert_sql
- multitableinserts_sql
- oncondition_sql
- jsonextractquote_sql
- jsonexists_sql
- arrayagg_sql
- slice_sql
- apply_sql
- grant_sql
- revoke_sql
- grantprivilege_sql
- grantprincipal_sql
- columns_sql
- overlay_sql
- todouble_sql
- string_sql
- median_sql
- overflowtruncatebehavior_sql
- unixseconds_sql
- 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_name
- weekstart_sql
- chr_sql
- block_sql
- functionspecification_sql
- storedprocedure_sql
- ifblock_sql
- casestatement_sql
- whileblock_sql
- loopblock_sql
- repeatblock_sql
- leave_sql
- iterate_sql
- execute_sql
- executesql_sql
- altermodifysqlsecurity_sql
- usingproperty_sql
- renameindex_sql