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

Generator converts a given syntax tree to the corresponding SQL string.

Arguments:
  • pretty: Whether to format the produced SQL string. Default: False.
  • identify: Determines when an identifier should be quoted. Possible values are: False (default): Never quote, except in cases where it's mandatory by the dialect. True: Always quote except for specials cases. 'safe': Only quote identifiers that are case insensitive.
  • normalize: Whether to normalize identifiers to lowercase. Default: False.
  • pad: The pad size in a formatted string. For example, this affects the indentation of a projection in a query, relative to its nesting level. Default: 2.
  • indent: The indentation size in a formatted string. For example, this affects the indentation of subqueries and filters under a 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
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.ArrayContainsAll'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.ArrayOverlaps'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.AssumeColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.AutoRefreshProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.BackupProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CaseSpecificColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.math.Ceil'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CharacterSetColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CharacterSetProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.ClusteredColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CollateColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CommentColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.ConnectByRoot'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.string.ConvertToCharset'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CopyGrantsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CredentialsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.CurrentCatalog'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.SessionUser'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.constraints.DateFormatColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.DefaultColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ApiProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ApplicationProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CatalogProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ComputeProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.DatabaseProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.DynamicProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.EmptyProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.EncodeColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.EndStatement'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.EnviromentProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.HandlerProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ParameterStyleProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.EphemeralColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.ExcludeColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ExecuteAsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Except'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ExternalProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.math.Floor'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Get'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.GlobalProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.HeapProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.HybridProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.IcebergProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.InheritsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.InlineLengthColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.InputModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Intersect'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.datatypes.IntervalSpan'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.Int64'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONBContainsAnyTopKeys'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONBContainsAllTopKeys'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONBDeleteAtPath'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONObject'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONObjectAgg'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.LanguageProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.LocationProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.LogProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.MaskingProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.MaterializedProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.NetFunc'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.NetworkProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.NonClusteredColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.NoPrimaryIndexProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.NotForReplicationColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.OnCommitProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.OnProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.OnUpdateColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.Operator'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.OutputModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.ExtendsLeft'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.ExtendsRight'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.PathColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.PartitionedByBucket'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.PartitionByTruncate'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.PivotAny'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.PositionalColumn'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.ProjectionPolicyColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.InvisibleColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.ZeroFillColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Put'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.RemoteWithConnectionModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ReturnsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.RowAccessProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.SafeFunc'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SampleProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SecureProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SecurityIntegrationProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SetConfigProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SetProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SettingsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SharingProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SqlReadWriteProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SqlSecurityProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.StabilityProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Stream'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.StreamingTableProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.StrictProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ddl.SwapTable'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.TableColumn'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.Tags'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.TemporaryProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.TitleColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.ToMap'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ToTableProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.TransformModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.TransientProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.VirtualProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ddl.TriggerExecute'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Union'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.UnloggedProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.UsingTemplateProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.UsingData'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.UppercaseColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.temporal.UtcDate'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.temporal.UtcTime'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.UtcTimestamp'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.query.Variadic'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.VarMap'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ViewAttributeProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.VolatileProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.WithJournalTableProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.WithProcedureOptions'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.WithSchemaBindingProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.WithOperator'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ForceProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.aggregate.ArrayAgg'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.math.BitwiseAndAgg'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.math.BitwiseOrAgg'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.math.BitwiseXorAgg'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.math.BitwiseCount'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.string.Chr'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.CurrentDate'>: <function no_paren_current_date_sql>, <class 'sqlglot.expressions.functions.CurrentVersion'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.DateDiff'>: <function _remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.temporal.DateAdd'>: <function _remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.temporal.DateStrToDate'>: <function datestrtodate_sql>, <class 'sqlglot.expressions.temporal.DateSub'>: <function _remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.temporal.DateTrunc'>: <function _date_trunc_sql>, <class 'sqlglot.expressions.temporal.Day'>: <function _remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.temporal.DayOfMonth'>: <function _remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.temporal.DayOfWeek'>: <function _remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.temporal.DayOfYear'>: <function _remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.aggregate.GroupConcat'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.core.ILike'>: <function no_ilike_sql>, <class 'sqlglot.expressions.json.JSONExtractScalar'>: <function arrow_json_extract_sql>, <class 'sqlglot.expressions.string.Length'>: <function length_or_char_length_sql>, <class 'sqlglot.expressions.aggregate.LogicalOr'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.aggregate.LogicalAnd'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.aggregate.Max'>: <function max_or_greatest>, <class 'sqlglot.expressions.aggregate.Min'>: <function min_or_least>, <class 'sqlglot.expressions.temporal.Month'>: <function _remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.core.NullSafeEQ'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.core.NullSafeNEQ'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.string.NumberToStr'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.query.Pivot'>: <function no_pivot_sql>, <class 'sqlglot.expressions.query.Select'>: <function preprocess.<locals>._to_sql>, <class 'sqlglot.expressions.string.StrPosition'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.StrToDate'>: <function _str_to_date_sql>, <class 'sqlglot.expressions.temporal.StrToTime'>: <function _str_to_date_sql>, <class 'sqlglot.expressions.string.Stuff'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.query.TableSample'>: <function no_tablesample_sql>, <class 'sqlglot.expressions.temporal.TimeFromParts'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.TimestampAdd'>: <function date_add_interval_sql.<locals>.func>, <class 'sqlglot.expressions.temporal.TimestampDiff'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.TimestampSub'>: <function date_add_interval_sql.<locals>.func>, <class 'sqlglot.expressions.temporal.TimeStrToUnix'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.TimeStrToTime'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.TimeToStr'>: <function _remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.string.Trim'>: <function trim_sql>, <class 'sqlglot.expressions.math.Trunc'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.functions.TryCast'>: <function no_trycast_sql>, <class 'sqlglot.expressions.temporal.TsOrDsAdd'>: <function date_add_sql.<locals>.func>, <class 'sqlglot.expressions.temporal.TsOrDsDiff'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.TsOrDsToDate'>: <function _ts_or_ds_to_date_sql>, <class 'sqlglot.expressions.string.Unicode'>: <function MySQLGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.UnixToTime'>: <function _unix_to_time_sql>, <class 'sqlglot.expressions.temporal.Week'>: <function _remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.temporal.WeekOfYear'>: <function _remove_ts_or_ds_to_date.<locals>.func>, <class 'sqlglot.expressions.temporal.Year'>: <function _remove_ts_or_ds_to_date.<locals>.func>}
UNSIGNED_TYPE_MAPPING = {<DType.UBIGINT: 'UBIGINT'>: 'BIGINT', <DType.UINT: 'UINT'>: 'INT', <DType.UMEDIUMINT: 'UMEDIUMINT'>: 'MEDIUMINT', <DType.USMALLINT: 'USMALLINT'>: 'SMALLINT', <DType.UTINYINT: 'UTINYINT'>: 'TINYINT', <DType.UDECIMAL: 'UDECIMAL'>: 'DECIMAL', <DType.UDOUBLE: 'UDOUBLE'>: 'DOUBLE'}
TIMESTAMP_TYPE_MAPPING = {<DType.DATETIME2: 'DATETIME2'>: 'DATETIME', <DType.SMALLDATETIME: 'SMALLDATETIME'>: 'DATETIME', <DType.TIMESTAMP: 'TIMESTAMP'>: 'DATETIME', <DType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>: 'DATETIME', <DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>: 'TIMESTAMP', <DType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>: 'TIMESTAMP'}
TYPE_MAPPING: ClassVar = {<DType.NCHAR: 'NCHAR'>: 'CHAR', <DType.NVARCHAR: 'NVARCHAR'>: 'VARCHAR', <DType.INET: 'INET'>: 'INET', <DType.ROWVERSION: 'ROWVERSION'>: 'VARBINARY', <DType.UBIGINT: 'UBIGINT'>: 'BIGINT', <DType.UINT: 'UINT'>: 'INT', <DType.UMEDIUMINT: 'UMEDIUMINT'>: 'MEDIUMINT', <DType.USMALLINT: 'USMALLINT'>: 'SMALLINT', <DType.UTINYINT: 'UTINYINT'>: 'TINYINT', <DType.UDECIMAL: 'UDECIMAL'>: 'DECIMAL', <DType.UDOUBLE: 'UDOUBLE'>: 'DOUBLE', <DType.DATETIME2: 'DATETIME2'>: 'DATETIME', <DType.SMALLDATETIME: 'SMALLDATETIME'>: 'DATETIME', <DType.TIMESTAMP: 'TIMESTAMP'>: 'DATETIME', <DType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>: 'DATETIME', <DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>: 'TIMESTAMP', <DType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>: 'TIMESTAMP'}
PROPERTIES_LOCATION: ClassVar = {<class 'sqlglot.expressions.properties.AllowedValuesProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.AlgorithmProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.ApiProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.ApplicationProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.AutoIncrementProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.AutoRefreshProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.BackupProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.BlockCompressionProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.CatalogProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.CharacterSetProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ChecksumProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.CollateProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ComputeProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.CopyGrantsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.query.Cluster'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ClusteredByProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DistributedByProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DuplicateKeyProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DataBlocksizeProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.DatabaseProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.DataDeletionProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DefinerProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.DictRange'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DictProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DynamicProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.DistKeyProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DistStyleProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.EmptyProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.EncodeProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.EngineProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.EnviromentProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.HandlerProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ParameterStyleProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ExecuteAsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ExternalProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.FallbackProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.FileFormatProperty'>: <PropertiesLocation.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.properties.FreespaceProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.GlobalProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.HeapProperty'>: <PropertiesLocation.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.properties.HybridProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.InheritsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.IcebergProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.IncludeProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.InputModelProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.IsolatedLoadingProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.JournalProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.LanguageProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.LikeProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.LocationProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.LockProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.LockingProperty'>: <PropertiesLocation.POST_ALIAS: 'POST_ALIAS'>, <class 'sqlglot.expressions.properties.LogProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.MaskingProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.MaterializedProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.MergeBlockRatioProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.ModuleProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.NetworkProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.NoPrimaryIndexProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.OnProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.OnCommitProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.query.Order'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.OutputModelProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.PartitionedByProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.PartitionedOfProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.constraints.PrimaryKey'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.Property'>: <PropertiesLocation.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.properties.RefreshTriggerProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.RemoteWithConnectionModelProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ReturnsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.RollupProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.RowAccessProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.RowFormatProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.RowFormatDelimitedProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.RowFormatSerdeProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SampleProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SchemaCommentProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SecureProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.SecurityIntegrationProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.SerdeProperties'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.ddl.Set'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SettingsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SetProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.SetConfigProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SharingProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.ddl.SequenceProperties'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.ddl.TriggerProperties'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.SortKeyProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SqlReadWriteProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SqlSecurityProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.StabilityProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.StorageHandlerProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.StreamingTableProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.StrictProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.Tags'>: <PropertiesLocation.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.properties.TemporaryProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.ToTableProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.TransientProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.TransformModelProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.ddl.MergeTreeTTL'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.UnloggedProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.UsingProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.UsingTemplateProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ViewAttributeProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.VirtualProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.VolatileProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.WithDataProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.WithJournalTableProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.WithProcedureOptions'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.WithSchemaBindingProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.WithSystemVersioningProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ForceProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.PartitionByRangeProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.PartitionByListProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>}
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 = {<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 = {<DType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>}
RESERVED_KEYWORDS = {'iterate', 'json_table', 'grouping', 'limit', 'join', 'maxvalue', 'get', 'modifies', 'signal', 'create', 'of', 'asc', 'as', 'no_write_to_binlog', 'distinctrow', 'localtimestamp', 'having', 'virtual', 'left', 'escaped', 'real', 'each', 'double', 'read', 'tinyblob', 'exists', 'optionally', 'varchar', 'usage', 'false', 'into', 'write', 'load', 'current_user', 'enclosed', 'accessible', 'numeric', 'system', 'inout', 'utc_timestamp', 'default', 'specific', 'constraint', 'infile', 'day_microsecond', 'row_number', 'int8', 'both', 'rlike', 'leading', 'precision', 'window', 'update', 'current_date', 'order', 'second_microsecond', 'character', 'primary', 'kill', 'dual', 'empty', 'minute_microsecond', 'nth_value', 'mediumtext', 'sql_big_result', 'asensitive', 'return', 'using', 'hour_second', 'select', 'right', 'groups', 'div', 'all', 'cross', 'tinytext', 'exit', 'regexp', 'cursor', 'true', 'binary', 'collate', 'elseif', 'by', 'between', 'varcharacter', 'current_timestamp', 'key', 'stored', 'alter', 'or', 'column', 'decimal', 'drop', 'release', 'int3', 'bigint', 'utc_date', 'set', 'sql', 'mediumint', 'trailing', 'spatial', 'values', 'lines', 'sensitive', 'optimizer_costs', 'dec', 'current_time', 'deterministic', 'unique', 'starting', 'delete', 'index', 'if', 'varying', 'inner', 'io_after_gtids', 'not', 'insensitive', 'show', 'day_minute', 'sql_calc_found_rows', 'master_ssl_verify_server_cert', 'schemas', 'percent_rank', 'in', 'int1', 'case', 'minute_second', 'high_priority', 'io_before_gtids', 'unlock', 'unsigned', 'loop', 'float8', 'lead', 'zerofill', 'cascade', 'mediumblob', 'foreign', 'add', 'day_second', 'optimize', 'partition', 'desc', 'describe', 'lock', 'sqlwarning', 'insert', 'int2', 'rename', 'match', 'declare', 'interval', 'convert', 'fetch', 'restrict', 'out', 'ignore', 'sqlexception', 'sqlstate', 'longtext', 'analyze', 'then', 'master_bind', 'mod', 'to', 'union', 'before', 'day_hour', 'change', 'repeat', 'separator', 'is', 'revoke', 'last_value', 'option', 'rows', 'fulltext', 'range', 'trigger', 'longblob', 'dense_rank', 'middleint', 'undo', 'leave', 'check', 'terminated', 'lateral', 'linear', 'schema', 'float4', 'delayed', 'cube', 'require', 'like', 'table', 'row', 'int', 'natural', 'with', 'rank', 'lag', 'low_priority', 'group', 'blob', 'references', 'float', 'hour_minute', 'procedure', 'localtime', 'sql_small_result', 'year_month', 'outfile', 'varbinary', 'outer', 'tinyint', 'except', 'generated', 'replace', 'reads', 'else', 'while', 'smallint', 'null', 'distinct', 'grant', 'integer', 'where', 'int4', 'from', 'explain', 'continue', 'keys', 'use', 'cume_dist', 'recursive', 'hour_microsecond', 'read_write', 'purge', 'first_value', 'condition', 'intersect', 'straight_join', 'on', 'over', 'database', 'ssl', 'utc_time', 'call', 'databases', 'function', 'when', 'for', 'xor', 'resignal', 'long', 'char', 'force', 'and', 'ntile'}
SQL_SECURITY_VIEW_LOCATION = <PropertiesLocation.POST_CREATE: 'POST_CREATE'>
def locate_properties( self, properties: sqlglot.expressions.properties.Properties) -> collections.defaultdict:
594    def locate_properties(self, properties: exp.Properties) -> defaultdict:
595        locations = super().locate_properties(properties)
596
597        # MySQL puts SQL SECURITY before VIEW but after the schema for functions/procedures
598        if isinstance(create := properties.parent, exp.Create) and create.kind == "VIEW":
599            post_schema = locations[exp.Properties.Location.POST_SCHEMA]
600            for i, p in enumerate(post_schema):
601                if isinstance(p, exp.SqlSecurityProperty):
602                    post_schema.pop(i)
603                    locations[self.SQL_SECURITY_VIEW_LOCATION].append(p)
604                    break
605
606        return locations
def computedcolumnconstraint_sql( self, expression: sqlglot.expressions.constraints.ComputedColumnConstraint) -> str:
608    def computedcolumnconstraint_sql(self, expression: exp.ComputedColumnConstraint) -> str:
609        persisted = "STORED" if expression.args.get("persisted") else "VIRTUAL"
610        return f"GENERATED ALWAYS AS ({self.sql(expression.this.unnest())}) {persisted}"
def array_sql(self, expression: sqlglot.expressions.array.Array) -> str:
612    def array_sql(self, expression: exp.Array) -> str:
613        self.unsupported("Arrays are not supported by MySQL")
614        return self.function_fallback_sql(expression)
def arraycontainsall_sql(self, expression: sqlglot.expressions.array.ArrayContainsAll) -> str:
616    def arraycontainsall_sql(self, expression: exp.ArrayContainsAll) -> str:
617        self.unsupported("Array operations are not supported by MySQL")
618        return self.function_fallback_sql(expression)
def dpipe_sql(self, expression: sqlglot.expressions.core.DPipe) -> str:
620    def dpipe_sql(self, expression: exp.DPipe) -> str:
621        return self.func("CONCAT", *expression.flatten())
def extract_sql(self, expression: sqlglot.expressions.temporal.Extract) -> str:
623    def extract_sql(self, expression: exp.Extract) -> str:
624        unit = expression.name
625        if unit and unit.lower() == "epoch":
626            return self.func("UNIX_TIMESTAMP", expression.expression)
627
628        return super().extract_sql(expression)
def datatype_sql(self, expression: sqlglot.expressions.datatypes.DataType) -> str:
630    def datatype_sql(self, expression: exp.DataType) -> str:
631        if (
632            self.VARCHAR_REQUIRES_SIZE
633            and expression.is_type(exp.DType.VARCHAR)
634            and not expression.expressions
635        ):
636            # `VARCHAR` must always have a size - if it doesn't, we always generate `TEXT`
637            return "TEXT"
638
639        # https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html
640        result = super().datatype_sql(expression)
641        if expression.this in self.UNSIGNED_TYPE_MAPPING:
642            result = f"{result} UNSIGNED"
643
644        return result
def jsonarraycontains_sql(self, expression: sqlglot.expressions.json.JSONArrayContains) -> str:
646    def jsonarraycontains_sql(self, expression: exp.JSONArrayContains) -> str:
647        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:
649    def cast_sql(self, expression: exp.Cast, safe_prefix: str | None = None) -> str:
650        if expression.to.this in self.TIMESTAMP_FUNC_TYPES:
651            return self.func("TIMESTAMP", expression.this)
652
653        to = self.CAST_MAPPING.get(expression.to.this)
654
655        if to:
656            expression.to.set("this", to)
657        return super().cast_sql(expression)
def show_sql(self, expression: sqlglot.expressions.ddl.Show) -> str:
659    def show_sql(self, expression: exp.Show) -> str:
660        this = f" {expression.name}"
661        full = " FULL" if expression.args.get("full") else ""
662        global_ = " GLOBAL" if expression.args.get("global_") else ""
663
664        target = self.sql(expression, "target")
665        target = f" {target}" if target else ""
666        if expression.name in ("COLUMNS", "INDEX"):
667            target = f" FROM{target}"
668        elif expression.name == "GRANTS":
669            target = f" FOR{target}"
670        elif expression.name in ("LINKS", "PARTITIONS"):
671            target = f" ON{target}" if target else ""
672        elif expression.name == "PROJECTIONS":
673            target = f" ON TABLE{target}" if target else ""
674
675        db = self._prefixed_sql("FROM", expression, "db")
676
677        like = self._prefixed_sql("LIKE", expression, "like")
678        where = self.sql(expression, "where")
679
680        types = self.expressions(expression, key="types")
681        types = f" {types}" if types else types
682        query = self._prefixed_sql("FOR QUERY", expression, "query")
683
684        if expression.name == "PROFILE":
685            offset = self._prefixed_sql("OFFSET", expression, "offset")
686            limit = self._prefixed_sql("LIMIT", expression, "limit")
687        else:
688            offset = ""
689            limit = self._oldstyle_limit_sql(expression)
690
691        log = self._prefixed_sql("IN", expression, "log")
692        position = self._prefixed_sql("FROM", expression, "position")
693
694        channel = self._prefixed_sql("FOR CHANNEL", expression, "channel")
695
696        if expression.name == "ENGINE":
697            mutex_or_status = " MUTEX" if expression.args.get("mutex") else " STATUS"
698        else:
699            mutex_or_status = ""
700
701        for_table = self._prefixed_sql("FOR TABLE", expression, "for_table")
702        for_group = self._prefixed_sql("FOR GROUP", expression, "for_group")
703        for_user = self._prefixed_sql("FOR USER", expression, "for_user")
704        for_role = self._prefixed_sql("FOR ROLE", expression, "for_role")
705        into_outfile = self._prefixed_sql("INTO OUTFILE", expression, "into_outfile")
706        json = " JSON" if expression.args.get("json") else ""
707
708        return f"SHOW{full}{global_}{this}{json}{target}{for_table}{types}{db}{query}{log}{position}{channel}{mutex_or_status}{like}{where}{offset}{limit}{for_group}{for_user}{for_role}{into_outfile}"
def alterrename_sql( self, expression: sqlglot.expressions.ddl.AlterRename, include_to: bool = True) -> str:
710    def alterrename_sql(self, expression: exp.AlterRename, include_to: bool = True) -> str:
711        """To avoid TO keyword in ALTER ... RENAME statements.
712        It's moved from Doris, because it's the same for all MySQL, Doris, and StarRocks.
713        """
714        return super().alterrename_sql(expression, include_to=False)

To avoid TO keyword in ALTER ... RENAME statements. It's moved from Doris, because it's the same for all MySQL, Doris, and StarRocks.

def altercolumn_sql(self, expression: sqlglot.expressions.ddl.AlterColumn) -> str:
716    def altercolumn_sql(self, expression: exp.AlterColumn) -> str:
717        dtype = self.sql(expression, "dtype")
718        if not dtype:
719            return super().altercolumn_sql(expression)
720
721        this = self.sql(expression, "this")
722        return f"MODIFY COLUMN {this} {dtype}"
def timestamptrunc_sql(self, expression: sqlglot.expressions.temporal.TimestampTrunc) -> str:
736    def timestamptrunc_sql(self, expression: exp.TimestampTrunc) -> str:
737        unit = expression.args.get("unit")
738
739        # Pick an old-enough date to avoid negative timestamp diffs
740        start_ts = "'0000-01-01 00:00:00'"
741
742        # Source: https://stackoverflow.com/a/32955740
743        timestamp_diff = build_date_delta(exp.TimestampDiff)([unit, start_ts, expression.this])
744        interval = exp.Interval(this=timestamp_diff, unit=unit)
745        dateadd = build_date_delta_with_interval(exp.DateAdd)([start_ts, interval])
746
747        return self.sql(dateadd)
def converttimezone_sql(self, expression: sqlglot.expressions.temporal.ConvertTimezone) -> str:
749    def converttimezone_sql(self, expression: exp.ConvertTimezone) -> str:
750        from_tz = expression.args.get("source_tz")
751        to_tz = expression.args.get("target_tz")
752        dt = expression.args.get("timestamp")
753
754        return self.func("CONVERT_TZ", dt, from_tz, to_tz)
def attimezone_sql(self, expression: sqlglot.expressions.core.AtTimeZone) -> str:
756    def attimezone_sql(self, expression: exp.AtTimeZone) -> str:
757        self.unsupported("AT TIME ZONE is not supported by MySQL")
758        return self.sql(expression.this)
def isascii_sql(self, expression: sqlglot.expressions.string.IsAscii) -> str:
760    def isascii_sql(self, expression: exp.IsAscii) -> str:
761        return f"REGEXP_LIKE({self.sql(expression.this)}, '^[[:ascii:]]*$')"
def ignorenulls_sql(self, expression: sqlglot.expressions.core.IgnoreNulls) -> str:
763    def ignorenulls_sql(self, expression: exp.IgnoreNulls) -> str:
764        # https://dev.mysql.com/doc/refman/8.4/en/window-function-descriptions.html
765        self.unsupported("MySQL does not support IGNORE NULLS.")
766        return self.sql(expression.this)
@unsupported_args('this')
def currentschema_sql(self, expression: sqlglot.expressions.functions.CurrentSchema) -> str:
768    @unsupported_args("this")
769    def currentschema_sql(self, expression: exp.CurrentSchema) -> str:
770        return self.func("SCHEMA")
def partition_sql(self, expression: sqlglot.expressions.query.Partition) -> str:
772    def partition_sql(self, expression: exp.Partition) -> str:
773        parent = expression.parent
774        if isinstance(parent, (exp.PartitionByRangeProperty, exp.PartitionByListProperty)):
775            return self.expressions(expression, flat=True)
776        return super().partition_sql(expression)
def partitionbyrangeproperty_sql( self, expression: sqlglot.expressions.properties.PartitionByRangeProperty) -> str:
785    def partitionbyrangeproperty_sql(self, expression: exp.PartitionByRangeProperty) -> str:
786        return self._partition_by_sql(expression, "RANGE")
def partitionbylistproperty_sql( self, expression: sqlglot.expressions.properties.PartitionByListProperty) -> str:
788    def partitionbylistproperty_sql(self, expression: exp.PartitionByListProperty) -> str:
789        return self._partition_by_sql(expression, "LIST")
def partitionlist_sql(self, expression: sqlglot.expressions.properties.PartitionList) -> str:
791    def partitionlist_sql(self, expression: exp.PartitionList) -> str:
792        name = self.sql(expression, "this")
793        values = self.expressions(expression, flat=True)
794        return f"PARTITION {name} VALUES IN ({values})"
def partitionrange_sql(self, expression: sqlglot.expressions.query.PartitionRange) -> str:
796    def partitionrange_sql(self, expression: exp.PartitionRange) -> str:
797        name = self.sql(expression, "this")
798        values = self.expressions(expression, flat=True)
799        return f"PARTITION {name} VALUES LESS THAN ({values})"
Inherited Members
sqlglot.generator.Generator
Generator
WINDOW_FUNCS_WITH_NULL_ORDERING
IGNORE_NULLS_IN_FUNC
IGNORE_NULLS_BEFORE_ORDER
EXCEPT_INTERSECT_SUPPORT_ALL_CLAUSE
CREATE_FUNCTION_RETURN_AS
MATCHED_BY_SOURCE
SUPPORTS_MERGE_WHERE
SINGLE_STRING_INTERVAL
RENAME_TABLE_WITH_DB
GROUPINGS_SEP
INDEX_ON
INOUT_SEPARATOR
DIRECTED_JOINS
QUERY_HINTS
IS_BOOL_ALLOWED
LIMIT_IS_TOP
RETURNING_END
EXTRACT_ALLOWS_QUOTES
TZ_TO_WITH_TIME_ZONE
ALTER_TABLE_INCLUDE_COLUMN_KEYWORD
UNNEST_WITH_ORDINALITY
AGGREGATE_FILTER_SUPPORTED
SEMI_ANTI_JOIN_WITH_SIDE
COMPUTED_COLUMN_WITH_TYPE
SUPPORTS_TABLE_COPY
TABLESAMPLE_REQUIRES_PARENS
TABLESAMPLE_SIZE_IS_ROWS
TABLESAMPLE_KEYWORDS
TABLESAMPLE_WITH_METHOD
TABLESAMPLE_SEED_KEYWORD
COLLATE_IS_FUNC
DATA_TYPE_SPECIFIERS_ALLOWED
ENSURE_BOOLS
CTE_RECURSIVE_KEYWORD_REQUIRED
SUPPORTS_SINGLE_ARG_CONCAT
SUPPORTS_TABLE_ALIAS_COLUMNS
SUPPORTS_NAMED_CTE_COLUMNS
UNPIVOT_ALIASES_ARE_IDENTIFIERS
INSERT_OVERWRITE
SUPPORTS_SELECT_INTO
SUPPORTS_UNLOGGED_TABLES
SUPPORTS_CREATE_TABLE_LIKE
LIKE_PROPERTY_INSIDE_SCHEMA
MULTI_ARG_DISTINCT
JSON_PATH_SINGLE_QUOTE_ESCAPE
SUPPORTED_JSON_PATH_PARTS
CAN_IMPLEMENT_ARRAY_ANY
SUPPORTS_WINDOW_EXCLUDE
SET_OP_MODIFIERS
COPY_PARAMS_ARE_WRAPPED
COPY_PARAMS_EQ_REQUIRED
COPY_HAS_INTO_KEYWORD
UNICODE_SUBSTITUTE
STAR_EXCEPT
HEX_FUNC
WITH_PROPERTIES_PREFIX
QUOTE_JSON_PATH
SUPPORTS_EXPLODING_PROJECTIONS
ARRAY_CONCAT_IS_VAR_LEN
SUPPORTS_CONVERT_TIMEZONE
SUPPORTS_UNIX_SECONDS
ALTER_SET_WRAPPED
NORMALIZE_EXTRACT_DATE_PARTS
ARRAY_SIZE_NAME
ALTER_SET_TYPE
ARRAY_SIZE_DIM_REQUIRED
SUPPORTS_BETWEEN_FLAGS
SUPPORTS_LIKE_QUANTIFIERS
MATCH_AGAINST_TABLE_PREFIX
SET_ASSIGNMENT_REQUIRES_VARIABLE_KEYWORD
DECLARE_DEFAULT_ASSIGNMENT
STAR_EXCLUDE_REQUIRES_DERIVED_TABLE
SUPPORTS_DROP_ALTER_ICEBERG_PROPERTY
UNSUPPORTED_TYPES
TYPE_PARAM_SETTINGS
TIME_PART_SINGULARS
TOKEN_MAPPING
STRUCT_DELIMITER
PARAMETER_TOKEN
NAMED_PLACEHOLDER_TOKEN
EXPRESSION_PRECEDES_PROPERTIES_CREATABLES
WITH_SEPARATED_COMMENTS
EXCLUDE_COMMENTS
UNWRAPPED_INTERVAL_VALUES
PARAMETERIZABLE_TEXT_TYPES
EXPRESSIONS_WITHOUT_NESTED_CTES
RESPECT_IGNORE_NULLS_UNSUPPORTED_EXPRESSIONS
SAFE_JSON_PATH_KEY_RE
SENTINEL_LINE_BREAK
pretty
identify
normalize
pad
unsupported_level
max_unsupported
leading_comma
max_text_width
comments
dialect
normalize_functions
unsupported_messages
generate
preprocess
unsupported
sep
seg
sanitize_comment
maybe_comment
wrap
no_identify
normalize_func
indent
sql
uncache_sql
cache_sql
characterset_sql
column_parts
column_sql
pseudocolumn_sql
columnposition_sql
columndef_sql
columnconstraint_sql
autoincrementcolumnconstraint_sql
compresscolumnconstraint_sql
generatedasidentitycolumnconstraint_sql
generatedasrowcolumnconstraint_sql
periodforsystemtimeconstraint_sql
notnullcolumnconstraint_sql
primarykeycolumnconstraint_sql
uniquecolumnconstraint_sql
inoutcolumnconstraint_sql
createable_sql
create_sql
sequenceproperties_sql
triggerproperties_sql
triggerreferencing_sql
triggerevent_sql
clone_sql
describe_sql
heredoc_sql
prepend_ctes
with_sql
cte_sql
tablealias_sql
bitstring_sql
hexstring_sql
bytestring_sql
unicodestring_sql
rawstring_sql
datatypeparam_sql
datatype_param_bound_limiter
directory_sql
delete_sql
drop_sql
set_operation
set_operations
fetch_sql
limitoptions_sql
filter_sql
hint_sql
indexparameters_sql
index_sql
identifier_sql
hex_sql
lowerhex_sql
inputoutputformat_sql
national_sql
properties_sql
root_properties
properties
with_properties
property_name
property_sql
uuidproperty_sql
likeproperty_sql
fallbackproperty_sql
journalproperty_sql
freespaceproperty_sql
checksumproperty_sql
mergeblockratioproperty_sql
moduleproperty_sql
datablocksizeproperty_sql
blockcompressionproperty_sql
isolatedloadingproperty_sql
partitionboundspec_sql
partitionedofproperty_sql
lockingproperty_sql
withdataproperty_sql
withsystemversioningproperty_sql
insert_sql
introducer_sql
kill_sql
pseudotype_sql
objectidentifier_sql
onconflict_sql
returning_sql
rowformatdelimitedproperty_sql
withtablehint_sql
indextablehint_sql
historicaldata_sql
table_parts
table_sql
tablefromrows_sql
tablesample_sql
pivot_sql
version_sql
tuple_sql
update_sql
values_sql
var_sql
into_sql
from_sql
groupingsets_sql
rollup_sql
rollupindex_sql
rollupproperty_sql
cube_sql
group_sql
having_sql
connect_sql
prior_sql
join_sql
lambda_sql
lateral_op
lateral_sql
limit_sql
offset_sql
setitem_sql
set_sql
queryband_sql
pragma_sql
lock_sql
literal_sql
escape_str
loaddata_sql
null_sql
boolean_sql
booland_sql
boolor_sql
order_sql
withfill_sql
cluster_sql
distribute_sql
sort_sql
ordered_sql
matchrecognizemeasure_sql
matchrecognize_sql
query_modifiers
options_modifier
for_modifiers
queryoption_sql
offset_limit_modifiers
after_limit_modifiers
select_sql
schema_sql
schema_columns_sql
star_sql
parameter_sql
sessionparameter_sql
placeholder_sql
subquery_sql
qualify_sql
unnest_sql
prewhere_sql
where_sql
window_sql
partition_by_sql
windowspec_sql
withingroup_sql
between_sql
bracket_offset_expressions
bracket_sql
all_sql
any_sql
exists_sql
case_sql
constraint_sql
nextvaluefor_sql
trim_sql
convert_concat_args
concat_sql
concatws_sql
check_sql
foreignkey_sql
primarykey_sql
if_sql
matchagainst_sql
jsonkeyvalue_sql
jsonpath_sql
json_path_part
formatjson_sql
formatphrase_sql
jsonarray_sql
jsonarrayagg_sql
jsoncolumndef_sql
jsonschema_sql
jsontable_sql
openjsoncolumndef_sql
openjson_sql
in_sql
in_unnest_op
interval_sql
return_sql
reference_sql
anonymous_sql
paren_sql
neg_sql
not_sql
alias_sql
pivotalias_sql
aliases_sql
atindex_sql
fromtimezone_sql
add_sql
and_sql
or_sql
xor_sql
connector_sql
bitwiseand_sql
bitwiseleftshift_sql
bitwisenot_sql
bitwiseor_sql
bitwiserightshift_sql
bitwisexor_sql
strtotime_sql
currentdate_sql
collate_sql
command_sql
comment_sql
mergetreettlaction_sql
mergetreettl_sql
transaction_sql
commit_sql
rollback_sql
modifycolumn_sql
alterindex_sql
alterdiststyle_sql
altersortkey_sql
renamecolumn_sql
alterset_sql
alter_sql
altersession_sql
add_column_sql
droppartition_sql
dropprimarykey_sql
addconstraint_sql
addpartition_sql
distinct_sql
respectnulls_sql
havingmax_sql
intdiv_sql
div_sql
safedivide_sql
overlaps_sql
distance_sql
dot_sql
eq_sql
propertyeq_sql
escape_sql
glob_sql
gt_sql
gte_sql
is_sql
like_sql
ilike_sql
match_sql
similarto_sql
lt_sql
lte_sql
mod_sql
mul_sql
neq_sql
nullsafeeq_sql
nullsafeneq_sql
sub_sql
trycast_sql
jsoncast_sql
try_sql
log_sql
use_sql
binary
ceil_floor
function_fallback_sql
func
format_args
too_wide
format_time
expressions
op_expressions
naked_property
tag_sql
token_sql
userdefinedfunction_sql
joinhint_sql
kwarg_sql
when_sql
whens_sql
merge_sql
tochar_sql
tonumber_sql
dictproperty_sql
dictrange_sql
dictsubproperty_sql
duplicatekeyproperty_sql
uniquekeyproperty_sql
distributedbyproperty_sql
oncluster_sql
clusteredbyproperty_sql
anyvalue_sql
querytransform_sql
indexconstraintoption_sql
checkcolumnconstraint_sql
indexcolumnconstraint_sql
nvl2_sql
comprehension_sql
columnprefix_sql
opclass_sql
predict_sql
generateembedding_sql
generatetext_sql
generatetable_sql
generatebool_sql
generateint_sql
generatedouble_sql
mltranslate_sql
mlforecast_sql
aiforecast_sql
featuresattime_sql
vectorsearch_sql
forin_sql
refresh_sql
toarray_sql
tsordstotime_sql
tsordstotimestamp_sql
tsordstodatetime_sql
tsordstodate_sql
unixdate_sql
lastday_sql
dateadd_sql
arrayany_sql
struct_sql
truncatetable_sql
convert_sql
copyparameter_sql
credentials_sql
copy_sql
semicolon_sql
datadeletionproperty_sql
maskingpolicycolumnconstraint_sql
gapfill_sql
scope_resolution
scoperesolution_sql
parsejson_sql
rand_sql
changes_sql
pad_sql
summarize_sql
explodinggenerateseries_sql
json_sql
jsonvalue_sql
skipjsoncolumn_sql
conditionalinsert_sql
multitableinserts_sql
oncondition_sql
jsonextractquote_sql
jsonexists_sql
arrayagg_sql
slice_sql
apply_sql
grant_sql
revoke_sql
grantprivilege_sql
grantprincipal_sql
columns_sql
overlay_sql
todouble_sql
string_sql
median_sql
overflowtruncatebehavior_sql
unixseconds_sql
arraysize_sql
attach_sql
detach_sql
attachoption_sql
watermarkcolumnconstraint_sql
encodeproperty_sql
includeproperty_sql
xmlelement_sql
xmlkeyvalueoption_sql
partitionbyrangepropertydynamic_sql
unpivotcolumns_sql
analyzesample_sql
analyzestatistics_sql
analyzehistogram_sql
analyzedelete_sql
analyzelistchainedrows_sql
analyzevalidate_sql
analyze_sql
xmltable_sql
xmlnamespace_sql
export_sql
declare_sql
declareitem_sql
recursivewithsearch_sql
parameterizedagg_sql
anonymousaggfunc_sql
combinedaggfunc_sql
combinedparameterizedagg_sql
install_sql
get_put_sql
translatecharacters_sql
decodecase_sql
semanticview_sql
getextract_sql
datefromunixdate_sql
space_sql
buildproperty_sql
refreshtriggerproperty_sql
modelattribute_sql
directorystage_sql
uuid_sql
initcap_sql
localtime_sql
localtimestamp_sql
weekstart_sql
chr_sql
block_sql
storedprocedure_sql
ifblock_sql
whileblock_sql
execute_sql
executesql_sql
altermodifysqlsecurity_sql
usingproperty_sql
renameindex_sql