Edit on GitHub

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

def altercolumn_sql(self, expression: sqlglot.expressions.ddl.AlterColumn) -> str:
747    def altercolumn_sql(self, expression: exp.AlterColumn) -> str:
748        dtype = self.sql(expression, "dtype")
749        if not dtype:
750            return super().altercolumn_sql(expression)
751
752        if expression.args.get("exists"):
753            self.unsupported("ALTER COLUMN IF EXISTS is not supported by this dialect")
754
755        this = self.sql(expression, "this")
756        null_constraint = self._alter_column_null_constraint_sql(expression)
757        return f"MODIFY COLUMN {this} {dtype}{null_constraint}"
def timestamptrunc_sql(self, expression: sqlglot.expressions.temporal.TimestampTrunc) -> str:
771    def timestamptrunc_sql(self, expression: exp.TimestampTrunc) -> str:
772        unit = expression.args.get("unit")
773        if isinstance(unit, exp.WeekStart):
774            unit = exp.var(self.weekstart_name(unit))
775
776        # Pick an old-enough date to avoid negative timestamp diffs
777        start_ts = "'0000-01-01 00:00:00'"
778
779        # Source: https://stackoverflow.com/a/32955740
780        timestamp_diff = build_date_delta(exp.TimestampDiff)([unit, start_ts, expression.this])
781        interval = exp.Interval(this=timestamp_diff, unit=unit)
782        dateadd = build_date_delta_with_interval(exp.DateAdd)([start_ts, interval])
783
784        return self.sql(dateadd)
def converttimezone_sql(self, expression: sqlglot.expressions.temporal.ConvertTimezone) -> str:
786    def converttimezone_sql(self, expression: exp.ConvertTimezone) -> str:
787        from_tz = expression.args.get("source_tz")
788        to_tz = expression.args.get("target_tz")
789        dt = expression.args.get("timestamp")
790
791        return self.func("CONVERT_TZ", dt, from_tz, to_tz)
def attimezone_sql(self, expression: sqlglot.expressions.core.AtTimeZone) -> str:
793    def attimezone_sql(self, expression: exp.AtTimeZone) -> str:
794        self.unsupported("AT TIME ZONE is not supported by MySQL")
795        return self.sql(expression.this)
def isascii_sql(self, expression: sqlglot.expressions.string.IsAscii) -> str:
797    def isascii_sql(self, expression: exp.IsAscii) -> str:
798        return f"REGEXP_LIKE({self.sql(expression.this)}, '^[[:ascii:]]*$')"
def ignorenulls_sql(self, expression: sqlglot.expressions.core.IgnoreNulls) -> str:
800    def ignorenulls_sql(self, expression: exp.IgnoreNulls) -> str:
801        # https://dev.mysql.com/doc/refman/8.4/en/window-function-descriptions.html
802        self.unsupported("MySQL does not support IGNORE NULLS.")
803        return self.sql(expression.this)
@unsupported_args('this')
def currentschema_sql(self, expression: sqlglot.expressions.functions.CurrentSchema) -> str:
805    @unsupported_args("this")
806    def currentschema_sql(self, expression: exp.CurrentSchema) -> str:
807        return self.func("SCHEMA")
def partition_sql(self, expression: sqlglot.expressions.query.Partition) -> str:
809    def partition_sql(self, expression: exp.Partition) -> str:
810        parent = expression.parent
811        if isinstance(parent, (exp.PartitionByRangeProperty, exp.PartitionByListProperty)):
812            return self.expressions(expression, flat=True)
813        return super().partition_sql(expression)
def partitionbyrangeproperty_sql( self, expression: sqlglot.expressions.properties.PartitionByRangeProperty) -> str:
822    def partitionbyrangeproperty_sql(self, expression: exp.PartitionByRangeProperty) -> str:
823        return self._partition_by_sql(expression, "RANGE")
def partitionbylistproperty_sql( self, expression: sqlglot.expressions.properties.PartitionByListProperty) -> str:
825    def partitionbylistproperty_sql(self, expression: exp.PartitionByListProperty) -> str:
826        return self._partition_by_sql(expression, "LIST")
def partitionlist_sql(self, expression: sqlglot.expressions.properties.PartitionList) -> str:
828    def partitionlist_sql(self, expression: exp.PartitionList) -> str:
829        name = self.sql(expression, "this")
830        values = self.expressions(expression, flat=True)
831        return f"PARTITION {name} VALUES IN ({values})"
def partitionrange_sql(self, expression: sqlglot.expressions.query.PartitionRange) -> str:
833    def partitionrange_sql(self, expression: exp.PartitionRange) -> str:
834        name = self.sql(expression, "this")
835        values = self.expressions(expression, flat=True)
836        return f"PARTITION {name} VALUES LESS THAN ({values})"
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
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
COPY_PARAMS_ARE_WRAPPED
COPY_PARAMS_EQ_REQUIRED
COPY_HAS_INTO_KEYWORD
UNICODE_SUBSTITUTE
STAR_EXCEPT
HEX_FUNC
WITH_PROPERTIES_PREFIX
QUOTE_JSON_PATH
SUPPORTS_EXPLODING_PROJECTIONS
ARRAY_CONCAT_IS_VAR_LEN
SUPPORTS_CONVERT_TIMEZONE
SUPPORTS_UNIX_SECONDS
ALTER_SET_WRAPPED
NORMALIZE_EXTRACT_DATE_PARTS
ARRAY_SIZE_NAME
ALTER_SET_TYPE
ARRAY_SIZE_DIM_REQUIRED
SUPPORTS_BETWEEN_FLAGS
SUPPORTS_LIKE_QUANTIFIERS
MATCH_AGAINST_TABLE_PREFIX
SET_ASSIGNMENT_REQUIRES_VARIABLE_KEYWORD
DECLARE_DEFAULT_ASSIGNMENT
STAR_EXCLUDE_REQUIRES_DERIVED_TABLE
SUPPORTS_DROP_ALTER_ICEBERG_PROPERTY
UNSUPPORTED_TYPES
TYPE_PARAM_SETTINGS
TIME_PART_SINGULARS
TOKEN_MAPPING
STRUCT_DELIMITER
PARAMETER_TOKEN
NAMED_PLACEHOLDER_TOKEN
EXPRESSION_PRECEDES_PROPERTIES_CREATABLES
WITH_SEPARATED_COMMENTS
EXCLUDE_COMMENTS
UNWRAPPED_INTERVAL_VALUES
PARAMETERIZABLE_TEXT_TYPES
EXPRESSIONS_WITHOUT_NESTED_CTES
RESPECT_IGNORE_NULLS_UNSUPPORTED_EXPRESSIONS
SAFE_JSON_PATH_KEY_RE
SENTINEL_LINE_BREAK
pretty
identify
normalize
pad
unsupported_level
max_unsupported
leading_comma
max_text_width
comments
dialect
normalize_functions
unsupported_messages
generate
preprocess
unsupported
sep
seg
sanitize_comment
maybe_comment
wrap
no_identify
normalize_func
indent
sql
uncache_sql
cache_sql
characterset_sql
column_parts
column_sql
pseudocolumn_sql
columnposition_sql
columndef_sql
columnconstraint_sql
autoincrementcolumnconstraint_sql
compresscolumnconstraint_sql
generatedasidentitycolumnconstraint_sql
generatedasrowcolumnconstraint_sql
periodforsystemtimeconstraint_sql
notnullcolumnconstraint_sql
primarykeycolumnconstraint_sql
uniquecolumnconstraint_sql
inoutcolumnconstraint_sql
createable_sql
create_sql
sequenceproperties_sql
triggerproperties_sql
triggerreferencing_sql
triggerevent_sql
clone_sql
describe_sql
heredoc_sql
prepend_ctes
with_sql
cte_sql
tablealias_sql
bitstring_sql
hexstring_sql
bytestring_sql
unicodestring_sql
rawstring_sql
datatypeparam_sql
datatype_param_bound_limiter
directory_sql
delete_sql
drop_sql
set_operation
set_operations
fetch_sql
limitoptions_sql
filter_sql
hint_sql
indexparameters_sql
index_sql
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
comprehension_sql
columnprefix_sql
opclass_sql
predict_sql
generateembedding_sql
generatetext_sql
generatetable_sql
generatebool_sql
generateint_sql
generatedouble_sql
mltranslate_sql
mlforecast_sql
aiforecast_sql
featuresattime_sql
vectorsearch_sql
forin_sql
refresh_sql
toarray_sql
tsordstotime_sql
tsordstotimestamp_sql
tsordstodatetime_sql
tsordstodate_sql
unixdate_sql
lastday_sql
dateadd_sql
arrayany_sql
struct_sql
truncatetable_sql
convert_sql
copyparameter_sql
credentials_sql
copy_sql
semicolon_sql
datadeletionproperty_sql
maskingpolicycolumnconstraint_sql
gapfill_sql
scope_resolution
scoperesolution_sql
parsejson_sql
rand_sql
changes_sql
pad_sql
summarize_sql
explodinggenerateseries_sql
json_sql
jsonvalue_sql
skipjsoncolumn_sql
conditionalinsert_sql
multitableinserts_sql
oncondition_sql
jsonextractquote_sql
jsonexists_sql
arrayagg_sql
slice_sql
apply_sql
grant_sql
revoke_sql
grantprivilege_sql
grantprincipal_sql
columns_sql
overlay_sql
todouble_sql
string_sql
median_sql
overflowtruncatebehavior_sql
unixseconds_sql
arraysize_sql
attach_sql
detach_sql
attachoption_sql
watermarkcolumnconstraint_sql
encodeproperty_sql
includeproperty_sql
xmlelement_sql
xmlkeyvalueoption_sql
partitionbyrangepropertydynamic_sql
unpivotcolumns_sql
analyzesample_sql
analyzestatistics_sql
analyzehistogram_sql
analyzedelete_sql
analyzelistchainedrows_sql
analyzevalidate_sql
analyze_sql
xmltable_sql
xmlnamespace_sql
export_sql
declare_sql
declareitem_sql
recursivewithsearch_sql
parameterizedagg_sql
anonymousaggfunc_sql
combinedaggfunc_sql
combinedparameterizedagg_sql
install_sql
get_put_sql
translatecharacters_sql
decodecase_sql
semanticview_sql
getextract_sql
datefromunixdate_sql
space_sql
buildproperty_sql
refreshtriggerproperty_sql
modelattribute_sql
directorystage_sql
uuid_sql
initcap_sql
localtime_sql
localtimestamp_sql
weekstart_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