Edit on GitHub

# sqlglot.parser

View Source

       1from __future__ import annotations
       2
       3import logging
       4import typing as t
       5import itertools
       6from collections import defaultdict
       7
       8from sqlglot import exp
       9from sqlglot.errors import ErrorLevel, ParseError, concat_messages, merge_errors
      10from sqlglot.helper import apply_index_offset, ensure_list, seq_get
      11from sqlglot.time import format_time
      12from sqlglot.tokens import Token, Tokenizer, TokenType
      13from sqlglot.trie import TrieResult, in_trie, new_trie
      14
      15if t.TYPE_CHECKING:
      16    from sqlglot._typing import E, Lit
      17    from sqlglot.dialects.dialect import Dialect, DialectType
      18
      19    T = t.TypeVar("T")
      20    TCeilFloor = t.TypeVar("TCeilFloor", exp.Ceil, exp.Floor)
      21
      22logger = logging.getLogger("sqlglot")
      23
      24OPTIONS_TYPE = t.Dict[str, t.Sequence[t.Union[t.Sequence[str], str]]]
      25
      26
      27def build_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
      28    if len(args) == 1 and args[0].is_star:
      29        return exp.StarMap(this=args[0])
      30
      31    keys = []
      32    values = []
      33    for i in range(0, len(args), 2):
      34        keys.append(args[i])
      35        values.append(args[i + 1])
      36
      37    return exp.VarMap(keys=exp.array(*keys, copy=False), values=exp.array(*values, copy=False))
      38
      39
      40def build_like(args: t.List) -> exp.Escape | exp.Like:
      41    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
      42    return exp.Escape(this=like, expression=seq_get(args, 2)) if len(args) > 2 else like
      43
      44
      45def binary_range_parser(
      46    expr_type: t.Type[exp.Expression], reverse_args: bool = False
      47) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
      48    def _parse_binary_range(
      49        self: Parser, this: t.Optional[exp.Expression]
      50    ) -> t.Optional[exp.Expression]:
      51        expression = self._parse_bitwise()
      52        if reverse_args:
      53            this, expression = expression, this
      54        return self._parse_escape(self.expression(expr_type, this=this, expression=expression))
      55
      56    return _parse_binary_range
      57
      58
      59def build_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
      60    # Default argument order is base, expression
      61    this = seq_get(args, 0)
      62    expression = seq_get(args, 1)
      63
      64    if expression:
      65        if not dialect.LOG_BASE_FIRST:
      66            this, expression = expression, this
      67        return exp.Log(this=this, expression=expression)
      68
      69    return (exp.Ln if dialect.parser_class.LOG_DEFAULTS_TO_LN else exp.Log)(this=this)
      70
      71
      72def build_hex(args: t.List, dialect: Dialect) -> exp.Hex | exp.LowerHex:
      73    arg = seq_get(args, 0)
      74    return exp.LowerHex(this=arg) if dialect.HEX_LOWERCASE else exp.Hex(this=arg)
      75
      76
      77def build_lower(args: t.List) -> exp.Lower | exp.Hex:
      78    # LOWER(HEX(..)) can be simplified to LowerHex to simplify its transpilation
      79    arg = seq_get(args, 0)
      80    return exp.LowerHex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Lower(this=arg)
      81
      82
      83def build_upper(args: t.List) -> exp.Upper | exp.Hex:
      84    # UPPER(HEX(..)) can be simplified to Hex to simplify its transpilation
      85    arg = seq_get(args, 0)
      86    return exp.Hex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Upper(this=arg)
      87
      88
      89def build_extract_json_with_path(expr_type: t.Type[E]) -> t.Callable[[t.List, Dialect], E]:
      90    def _builder(args: t.List, dialect: Dialect) -> E:
      91        expression = expr_type(
      92            this=seq_get(args, 0), expression=dialect.to_json_path(seq_get(args, 1))
      93        )
      94        if len(args) > 2 and expr_type is exp.JSONExtract:
      95            expression.set("expressions", args[2:])
      96
      97        return expression
      98
      99    return _builder
     100
     101
     102def build_mod(args: t.List) -> exp.Mod:
     103    this = seq_get(args, 0)
     104    expression = seq_get(args, 1)
     105
     106    # Wrap the operands if they are binary nodes, e.g. MOD(a + 1, 7) -> (a + 1) % 7
     107    this = exp.Paren(this=this) if isinstance(this, exp.Binary) else this
     108    expression = exp.Paren(this=expression) if isinstance(expression, exp.Binary) else expression
     109
     110    return exp.Mod(this=this, expression=expression)
     111
     112
     113def build_pad(args: t.List, is_left: bool = True):
     114    return exp.Pad(
     115        this=seq_get(args, 0),
     116        expression=seq_get(args, 1),
     117        fill_pattern=seq_get(args, 2),
     118        is_left=is_left,
     119    )
     120
     121
     122def build_array_constructor(
     123    exp_class: t.Type[E], args: t.List, bracket_kind: TokenType, dialect: Dialect
     124) -> exp.Expression:
     125    array_exp = exp_class(expressions=args)
     126
     127    if exp_class == exp.Array and dialect.HAS_DISTINCT_ARRAY_CONSTRUCTORS:
     128        array_exp.set("bracket_notation", bracket_kind == TokenType.L_BRACKET)
     129
     130    return array_exp
     131
     132
     133def build_convert_timezone(
     134    args: t.List, default_source_tz: t.Optional[str] = None
     135) -> t.Union[exp.ConvertTimezone, exp.Anonymous]:
     136    if len(args) == 2:
     137        source_tz = exp.Literal.string(default_source_tz) if default_source_tz else None
     138        return exp.ConvertTimezone(
     139            source_tz=source_tz, target_tz=seq_get(args, 0), timestamp=seq_get(args, 1)
     140        )
     141
     142    return exp.ConvertTimezone.from_arg_list(args)
     143
     144
     145def build_trim(args: t.List, is_left: bool = True):
     146    return exp.Trim(
     147        this=seq_get(args, 0),
     148        expression=seq_get(args, 1),
     149        position="LEADING" if is_left else "TRAILING",
     150    )
     151
     152
     153def build_coalesce(args: t.List, is_nvl: t.Optional[bool] = None) -> exp.Coalesce:
     154    return exp.Coalesce(this=seq_get(args, 0), expressions=args[1:], is_nvl=is_nvl)
     155
     156
     157def build_locate_strposition(args: t.List):
     158    return exp.StrPosition(
     159        this=seq_get(args, 1),
     160        substr=seq_get(args, 0),
     161        position=seq_get(args, 2),
     162    )
     163
     164
     165class _Parser(type):
     166    def __new__(cls, clsname, bases, attrs):
     167        klass = super().__new__(cls, clsname, bases, attrs)
     168
     169        klass.SHOW_TRIE = new_trie(key.split(" ") for key in klass.SHOW_PARSERS)
     170        klass.SET_TRIE = new_trie(key.split(" ") for key in klass.SET_PARSERS)
     171
     172        return klass
     173
     174
     175class Parser(metaclass=_Parser):
     176    """
     177    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
     178
     179    Args:
     180        error_level: The desired error level.
     181            Default: ErrorLevel.IMMEDIATE
     182        error_message_context: The amount of context to capture from a query string when displaying
     183            the error message (in number of characters).
     184            Default: 100
     185        max_errors: Maximum number of error messages to include in a raised ParseError.
     186            This is only relevant if error_level is ErrorLevel.RAISE.
     187            Default: 3
     188    """
     189
     190    FUNCTIONS: t.Dict[str, t.Callable] = {
     191        **{name: func.from_arg_list for name, func in exp.FUNCTION_BY_NAME.items()},
     192        **dict.fromkeys(("COALESCE", "IFNULL", "NVL"), build_coalesce),
     193        "ARRAY": lambda args, dialect: exp.Array(expressions=args),
     194        "ARRAYAGG": lambda args, dialect: exp.ArrayAgg(
     195            this=seq_get(args, 0), nulls_excluded=dialect.ARRAY_AGG_INCLUDES_NULLS is None or None
     196        ),
     197        "ARRAY_AGG": lambda args, dialect: exp.ArrayAgg(
     198            this=seq_get(args, 0), nulls_excluded=dialect.ARRAY_AGG_INCLUDES_NULLS is None or None
     199        ),
     200        "CHAR": lambda args: exp.Chr(expressions=args),
     201        "CHR": lambda args: exp.Chr(expressions=args),
     202        "COUNT": lambda args: exp.Count(this=seq_get(args, 0), expressions=args[1:], big_int=True),
     203        "CONCAT": lambda args, dialect: exp.Concat(
     204            expressions=args,
     205            safe=not dialect.STRICT_STRING_CONCAT,
     206            coalesce=dialect.CONCAT_COALESCE,
     207        ),
     208        "CONCAT_WS": lambda args, dialect: exp.ConcatWs(
     209            expressions=args,
     210            safe=not dialect.STRICT_STRING_CONCAT,
     211            coalesce=dialect.CONCAT_COALESCE,
     212        ),
     213        "CONVERT_TIMEZONE": build_convert_timezone,
     214        "DATE_TO_DATE_STR": lambda args: exp.Cast(
     215            this=seq_get(args, 0),
     216            to=exp.DataType(this=exp.DataType.Type.TEXT),
     217        ),
     218        "GENERATE_DATE_ARRAY": lambda args: exp.GenerateDateArray(
     219            start=seq_get(args, 0),
     220            end=seq_get(args, 1),
     221            step=seq_get(args, 2) or exp.Interval(this=exp.Literal.string(1), unit=exp.var("DAY")),
     222        ),
     223        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
     224        "HEX": build_hex,
     225        "JSON_EXTRACT": build_extract_json_with_path(exp.JSONExtract),
     226        "JSON_EXTRACT_SCALAR": build_extract_json_with_path(exp.JSONExtractScalar),
     227        "JSON_EXTRACT_PATH_TEXT": build_extract_json_with_path(exp.JSONExtractScalar),
     228        "LIKE": build_like,
     229        "LOG": build_logarithm,
     230        "LOG2": lambda args: exp.Log(this=exp.Literal.number(2), expression=seq_get(args, 0)),
     231        "LOG10": lambda args: exp.Log(this=exp.Literal.number(10), expression=seq_get(args, 0)),
     232        "LOWER": build_lower,
     233        "LPAD": lambda args: build_pad(args),
     234        "LEFTPAD": lambda args: build_pad(args),
     235        "LTRIM": lambda args: build_trim(args),
     236        "MOD": build_mod,
     237        "RIGHTPAD": lambda args: build_pad(args, is_left=False),
     238        "RPAD": lambda args: build_pad(args, is_left=False),
     239        "RTRIM": lambda args: build_trim(args, is_left=False),
     240        "SCOPE_RESOLUTION": lambda args: exp.ScopeResolution(expression=seq_get(args, 0))
     241        if len(args) != 2
     242        else exp.ScopeResolution(this=seq_get(args, 0), expression=seq_get(args, 1)),
     243        "STRPOS": exp.StrPosition.from_arg_list,
     244        "CHARINDEX": lambda args: build_locate_strposition(args),
     245        "INSTR": exp.StrPosition.from_arg_list,
     246        "LOCATE": lambda args: build_locate_strposition(args),
     247        "TIME_TO_TIME_STR": lambda args: exp.Cast(
     248            this=seq_get(args, 0),
     249            to=exp.DataType(this=exp.DataType.Type.TEXT),
     250        ),
     251        "TO_HEX": build_hex,
     252        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
     253            this=exp.Cast(
     254                this=seq_get(args, 0),
     255                to=exp.DataType(this=exp.DataType.Type.TEXT),
     256            ),
     257            start=exp.Literal.number(1),
     258            length=exp.Literal.number(10),
     259        ),
     260        "UNNEST": lambda args: exp.Unnest(expressions=ensure_list(seq_get(args, 0))),
     261        "UPPER": build_upper,
     262        "VAR_MAP": build_var_map,
     263    }
     264
     265    NO_PAREN_FUNCTIONS = {
     266        TokenType.CURRENT_DATE: exp.CurrentDate,
     267        TokenType.CURRENT_DATETIME: exp.CurrentDate,
     268        TokenType.CURRENT_TIME: exp.CurrentTime,
     269        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
     270        TokenType.CURRENT_USER: exp.CurrentUser,
     271    }
     272
     273    STRUCT_TYPE_TOKENS = {
     274        TokenType.NESTED,
     275        TokenType.OBJECT,
     276        TokenType.STRUCT,
     277        TokenType.UNION,
     278    }
     279
     280    NESTED_TYPE_TOKENS = {
     281        TokenType.ARRAY,
     282        TokenType.LIST,
     283        TokenType.LOWCARDINALITY,
     284        TokenType.MAP,
     285        TokenType.NULLABLE,
     286        TokenType.RANGE,
     287        *STRUCT_TYPE_TOKENS,
     288    }
     289
     290    ENUM_TYPE_TOKENS = {
     291        TokenType.DYNAMIC,
     292        TokenType.ENUM,
     293        TokenType.ENUM8,
     294        TokenType.ENUM16,
     295    }
     296
     297    AGGREGATE_TYPE_TOKENS = {
     298        TokenType.AGGREGATEFUNCTION,
     299        TokenType.SIMPLEAGGREGATEFUNCTION,
     300    }
     301
     302    TYPE_TOKENS = {
     303        TokenType.BIT,
     304        TokenType.BOOLEAN,
     305        TokenType.TINYINT,
     306        TokenType.UTINYINT,
     307        TokenType.SMALLINT,
     308        TokenType.USMALLINT,
     309        TokenType.INT,
     310        TokenType.UINT,
     311        TokenType.BIGINT,
     312        TokenType.UBIGINT,
     313        TokenType.INT128,
     314        TokenType.UINT128,
     315        TokenType.INT256,
     316        TokenType.UINT256,
     317        TokenType.MEDIUMINT,
     318        TokenType.UMEDIUMINT,
     319        TokenType.FIXEDSTRING,
     320        TokenType.FLOAT,
     321        TokenType.DOUBLE,
     322        TokenType.UDOUBLE,
     323        TokenType.CHAR,
     324        TokenType.NCHAR,
     325        TokenType.VARCHAR,
     326        TokenType.NVARCHAR,
     327        TokenType.BPCHAR,
     328        TokenType.TEXT,
     329        TokenType.MEDIUMTEXT,
     330        TokenType.LONGTEXT,
     331        TokenType.BLOB,
     332        TokenType.MEDIUMBLOB,
     333        TokenType.LONGBLOB,
     334        TokenType.BINARY,
     335        TokenType.VARBINARY,
     336        TokenType.JSON,
     337        TokenType.JSONB,
     338        TokenType.INTERVAL,
     339        TokenType.TINYBLOB,
     340        TokenType.TINYTEXT,
     341        TokenType.TIME,
     342        TokenType.TIMETZ,
     343        TokenType.TIMESTAMP,
     344        TokenType.TIMESTAMP_S,
     345        TokenType.TIMESTAMP_MS,
     346        TokenType.TIMESTAMP_NS,
     347        TokenType.TIMESTAMPTZ,
     348        TokenType.TIMESTAMPLTZ,
     349        TokenType.TIMESTAMPNTZ,
     350        TokenType.DATETIME,
     351        TokenType.DATETIME2,
     352        TokenType.DATETIME64,
     353        TokenType.SMALLDATETIME,
     354        TokenType.DATE,
     355        TokenType.DATE32,
     356        TokenType.INT4RANGE,
     357        TokenType.INT4MULTIRANGE,
     358        TokenType.INT8RANGE,
     359        TokenType.INT8MULTIRANGE,
     360        TokenType.NUMRANGE,
     361        TokenType.NUMMULTIRANGE,
     362        TokenType.TSRANGE,
     363        TokenType.TSMULTIRANGE,
     364        TokenType.TSTZRANGE,
     365        TokenType.TSTZMULTIRANGE,
     366        TokenType.DATERANGE,
     367        TokenType.DATEMULTIRANGE,
     368        TokenType.DECIMAL,
     369        TokenType.DECIMAL32,
     370        TokenType.DECIMAL64,
     371        TokenType.DECIMAL128,
     372        TokenType.DECIMAL256,
     373        TokenType.UDECIMAL,
     374        TokenType.BIGDECIMAL,
     375        TokenType.UUID,
     376        TokenType.GEOGRAPHY,
     377        TokenType.GEOMETRY,
     378        TokenType.POINT,
     379        TokenType.RING,
     380        TokenType.LINESTRING,
     381        TokenType.MULTILINESTRING,
     382        TokenType.POLYGON,
     383        TokenType.MULTIPOLYGON,
     384        TokenType.HLLSKETCH,
     385        TokenType.HSTORE,
     386        TokenType.PSEUDO_TYPE,
     387        TokenType.SUPER,
     388        TokenType.SERIAL,
     389        TokenType.SMALLSERIAL,
     390        TokenType.BIGSERIAL,
     391        TokenType.XML,
     392        TokenType.YEAR,
     393        TokenType.USERDEFINED,
     394        TokenType.MONEY,
     395        TokenType.SMALLMONEY,
     396        TokenType.ROWVERSION,
     397        TokenType.IMAGE,
     398        TokenType.VARIANT,
     399        TokenType.VECTOR,
     400        TokenType.OBJECT,
     401        TokenType.OBJECT_IDENTIFIER,
     402        TokenType.INET,
     403        TokenType.IPADDRESS,
     404        TokenType.IPPREFIX,
     405        TokenType.IPV4,
     406        TokenType.IPV6,
     407        TokenType.UNKNOWN,
     408        TokenType.NOTHING,
     409        TokenType.NULL,
     410        TokenType.NAME,
     411        TokenType.TDIGEST,
     412        TokenType.DYNAMIC,
     413        *ENUM_TYPE_TOKENS,
     414        *NESTED_TYPE_TOKENS,
     415        *AGGREGATE_TYPE_TOKENS,
     416    }
     417
     418    SIGNED_TO_UNSIGNED_TYPE_TOKEN = {
     419        TokenType.BIGINT: TokenType.UBIGINT,
     420        TokenType.INT: TokenType.UINT,
     421        TokenType.MEDIUMINT: TokenType.UMEDIUMINT,
     422        TokenType.SMALLINT: TokenType.USMALLINT,
     423        TokenType.TINYINT: TokenType.UTINYINT,
     424        TokenType.DECIMAL: TokenType.UDECIMAL,
     425        TokenType.DOUBLE: TokenType.UDOUBLE,
     426    }
     427
     428    SUBQUERY_PREDICATES = {
     429        TokenType.ANY: exp.Any,
     430        TokenType.ALL: exp.All,
     431        TokenType.EXISTS: exp.Exists,
     432        TokenType.SOME: exp.Any,
     433    }
     434
     435    RESERVED_TOKENS = {
     436        *Tokenizer.SINGLE_TOKENS.values(),
     437        TokenType.SELECT,
     438    } - {TokenType.IDENTIFIER}
     439
     440    DB_CREATABLES = {
     441        TokenType.DATABASE,
     442        TokenType.DICTIONARY,
     443        TokenType.FILE_FORMAT,
     444        TokenType.MODEL,
     445        TokenType.NAMESPACE,
     446        TokenType.SCHEMA,
     447        TokenType.SEQUENCE,
     448        TokenType.SINK,
     449        TokenType.SOURCE,
     450        TokenType.STAGE,
     451        TokenType.STORAGE_INTEGRATION,
     452        TokenType.STREAMLIT,
     453        TokenType.TABLE,
     454        TokenType.TAG,
     455        TokenType.VIEW,
     456        TokenType.WAREHOUSE,
     457    }
     458
     459    CREATABLES = {
     460        TokenType.COLUMN,
     461        TokenType.CONSTRAINT,
     462        TokenType.FOREIGN_KEY,
     463        TokenType.FUNCTION,
     464        TokenType.INDEX,
     465        TokenType.PROCEDURE,
     466        *DB_CREATABLES,
     467    }
     468
     469    ALTERABLES = {
     470        TokenType.INDEX,
     471        TokenType.TABLE,
     472        TokenType.VIEW,
     473    }
     474
     475    # Tokens that can represent identifiers
     476    ID_VAR_TOKENS = {
     477        TokenType.ALL,
     478        TokenType.ATTACH,
     479        TokenType.VAR,
     480        TokenType.ANTI,
     481        TokenType.APPLY,
     482        TokenType.ASC,
     483        TokenType.ASOF,
     484        TokenType.AUTO_INCREMENT,
     485        TokenType.BEGIN,
     486        TokenType.BPCHAR,
     487        TokenType.CACHE,
     488        TokenType.CASE,
     489        TokenType.COLLATE,
     490        TokenType.COMMAND,
     491        TokenType.COMMENT,
     492        TokenType.COMMIT,
     493        TokenType.CONSTRAINT,
     494        TokenType.COPY,
     495        TokenType.CUBE,
     496        TokenType.CURRENT_SCHEMA,
     497        TokenType.DEFAULT,
     498        TokenType.DELETE,
     499        TokenType.DESC,
     500        TokenType.DESCRIBE,
     501        TokenType.DETACH,
     502        TokenType.DICTIONARY,
     503        TokenType.DIV,
     504        TokenType.END,
     505        TokenType.EXECUTE,
     506        TokenType.EXPORT,
     507        TokenType.ESCAPE,
     508        TokenType.FALSE,
     509        TokenType.FIRST,
     510        TokenType.FILTER,
     511        TokenType.FINAL,
     512        TokenType.FORMAT,
     513        TokenType.FULL,
     514        TokenType.IDENTIFIER,
     515        TokenType.IS,
     516        TokenType.ISNULL,
     517        TokenType.INTERVAL,
     518        TokenType.KEEP,
     519        TokenType.KILL,
     520        TokenType.LEFT,
     521        TokenType.LIMIT,
     522        TokenType.LOAD,
     523        TokenType.MERGE,
     524        TokenType.NATURAL,
     525        TokenType.NEXT,
     526        TokenType.OFFSET,
     527        TokenType.OPERATOR,
     528        TokenType.ORDINALITY,
     529        TokenType.OVERLAPS,
     530        TokenType.OVERWRITE,
     531        TokenType.PARTITION,
     532        TokenType.PERCENT,
     533        TokenType.PIVOT,
     534        TokenType.PRAGMA,
     535        TokenType.PUT,
     536        TokenType.RANGE,
     537        TokenType.RECURSIVE,
     538        TokenType.REFERENCES,
     539        TokenType.REFRESH,
     540        TokenType.RENAME,
     541        TokenType.REPLACE,
     542        TokenType.RIGHT,
     543        TokenType.ROLLUP,
     544        TokenType.ROW,
     545        TokenType.ROWS,
     546        TokenType.SEMI,
     547        TokenType.SET,
     548        TokenType.SETTINGS,
     549        TokenType.SHOW,
     550        TokenType.TEMPORARY,
     551        TokenType.TOP,
     552        TokenType.TRUE,
     553        TokenType.TRUNCATE,
     554        TokenType.UNIQUE,
     555        TokenType.UNNEST,
     556        TokenType.UNPIVOT,
     557        TokenType.UPDATE,
     558        TokenType.USE,
     559        TokenType.VOLATILE,
     560        TokenType.WINDOW,
     561        *CREATABLES,
     562        *SUBQUERY_PREDICATES,
     563        *TYPE_TOKENS,
     564        *NO_PAREN_FUNCTIONS,
     565    }
     566    ID_VAR_TOKENS.remove(TokenType.UNION)
     567
     568    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
     569        TokenType.ANTI,
     570        TokenType.APPLY,
     571        TokenType.ASOF,
     572        TokenType.FULL,
     573        TokenType.LEFT,
     574        TokenType.LOCK,
     575        TokenType.NATURAL,
     576        TokenType.RIGHT,
     577        TokenType.SEMI,
     578        TokenType.WINDOW,
     579    }
     580
     581    ALIAS_TOKENS = ID_VAR_TOKENS
     582
     583    COLON_PLACEHOLDER_TOKENS = ID_VAR_TOKENS
     584
     585    ARRAY_CONSTRUCTORS = {
     586        "ARRAY": exp.Array,
     587        "LIST": exp.List,
     588    }
     589
     590    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
     591
     592    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
     593
     594    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
     595
     596    FUNC_TOKENS = {
     597        TokenType.COLLATE,
     598        TokenType.COMMAND,
     599        TokenType.CURRENT_DATE,
     600        TokenType.CURRENT_DATETIME,
     601        TokenType.CURRENT_SCHEMA,
     602        TokenType.CURRENT_TIMESTAMP,
     603        TokenType.CURRENT_TIME,
     604        TokenType.CURRENT_USER,
     605        TokenType.FILTER,
     606        TokenType.FIRST,
     607        TokenType.FORMAT,
     608        TokenType.GLOB,
     609        TokenType.IDENTIFIER,
     610        TokenType.INDEX,
     611        TokenType.ISNULL,
     612        TokenType.ILIKE,
     613        TokenType.INSERT,
     614        TokenType.LIKE,
     615        TokenType.MERGE,
     616        TokenType.NEXT,
     617        TokenType.OFFSET,
     618        TokenType.PRIMARY_KEY,
     619        TokenType.RANGE,
     620        TokenType.REPLACE,
     621        TokenType.RLIKE,
     622        TokenType.ROW,
     623        TokenType.UNNEST,
     624        TokenType.VAR,
     625        TokenType.LEFT,
     626        TokenType.RIGHT,
     627        TokenType.SEQUENCE,
     628        TokenType.DATE,
     629        TokenType.DATETIME,
     630        TokenType.TABLE,
     631        TokenType.TIMESTAMP,
     632        TokenType.TIMESTAMPTZ,
     633        TokenType.TRUNCATE,
     634        TokenType.WINDOW,
     635        TokenType.XOR,
     636        *TYPE_TOKENS,
     637        *SUBQUERY_PREDICATES,
     638    }
     639
     640    CONJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
     641        TokenType.AND: exp.And,
     642    }
     643
     644    ASSIGNMENT: t.Dict[TokenType, t.Type[exp.Expression]] = {
     645        TokenType.COLON_EQ: exp.PropertyEQ,
     646    }
     647
     648    DISJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
     649        TokenType.OR: exp.Or,
     650    }
     651
     652    EQUALITY = {
     653        TokenType.EQ: exp.EQ,
     654        TokenType.NEQ: exp.NEQ,
     655        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
     656    }
     657
     658    COMPARISON = {
     659        TokenType.GT: exp.GT,
     660        TokenType.GTE: exp.GTE,
     661        TokenType.LT: exp.LT,
     662        TokenType.LTE: exp.LTE,
     663    }
     664
     665    BITWISE = {
     666        TokenType.AMP: exp.BitwiseAnd,
     667        TokenType.CARET: exp.BitwiseXor,
     668        TokenType.PIPE: exp.BitwiseOr,
     669    }
     670
     671    TERM = {
     672        TokenType.DASH: exp.Sub,
     673        TokenType.PLUS: exp.Add,
     674        TokenType.MOD: exp.Mod,
     675        TokenType.COLLATE: exp.Collate,
     676    }
     677
     678    FACTOR = {
     679        TokenType.DIV: exp.IntDiv,
     680        TokenType.LR_ARROW: exp.Distance,
     681        TokenType.SLASH: exp.Div,
     682        TokenType.STAR: exp.Mul,
     683    }
     684
     685    EXPONENT: t.Dict[TokenType, t.Type[exp.Expression]] = {}
     686
     687    TIMES = {
     688        TokenType.TIME,
     689        TokenType.TIMETZ,
     690    }
     691
     692    TIMESTAMPS = {
     693        TokenType.TIMESTAMP,
     694        TokenType.TIMESTAMPNTZ,
     695        TokenType.TIMESTAMPTZ,
     696        TokenType.TIMESTAMPLTZ,
     697        *TIMES,
     698    }
     699
     700    SET_OPERATIONS = {
     701        TokenType.UNION,
     702        TokenType.INTERSECT,
     703        TokenType.EXCEPT,
     704    }
     705
     706    JOIN_METHODS = {
     707        TokenType.ASOF,
     708        TokenType.NATURAL,
     709        TokenType.POSITIONAL,
     710    }
     711
     712    JOIN_SIDES = {
     713        TokenType.LEFT,
     714        TokenType.RIGHT,
     715        TokenType.FULL,
     716    }
     717
     718    JOIN_KINDS = {
     719        TokenType.ANTI,
     720        TokenType.CROSS,
     721        TokenType.INNER,
     722        TokenType.OUTER,
     723        TokenType.SEMI,
     724        TokenType.STRAIGHT_JOIN,
     725    }
     726
     727    JOIN_HINTS: t.Set[str] = set()
     728
     729    LAMBDAS = {
     730        TokenType.ARROW: lambda self, expressions: self.expression(
     731            exp.Lambda,
     732            this=self._replace_lambda(
     733                self._parse_assignment(),
     734                expressions,
     735            ),
     736            expressions=expressions,
     737        ),
     738        TokenType.FARROW: lambda self, expressions: self.expression(
     739            exp.Kwarg,
     740            this=exp.var(expressions[0].name),
     741            expression=self._parse_assignment(),
     742        ),
     743    }
     744
     745    COLUMN_OPERATORS = {
     746        TokenType.DOT: None,
     747        TokenType.DOTCOLON: lambda self, this, to: self.expression(
     748            exp.JSONCast,
     749            this=this,
     750            to=to,
     751        ),
     752        TokenType.DCOLON: lambda self, this, to: self.expression(
     753            exp.Cast if self.STRICT_CAST else exp.TryCast,
     754            this=this,
     755            to=to,
     756        ),
     757        TokenType.ARROW: lambda self, this, path: self.expression(
     758            exp.JSONExtract,
     759            this=this,
     760            expression=self.dialect.to_json_path(path),
     761            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
     762        ),
     763        TokenType.DARROW: lambda self, this, path: self.expression(
     764            exp.JSONExtractScalar,
     765            this=this,
     766            expression=self.dialect.to_json_path(path),
     767            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
     768        ),
     769        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
     770            exp.JSONBExtract,
     771            this=this,
     772            expression=path,
     773        ),
     774        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
     775            exp.JSONBExtractScalar,
     776            this=this,
     777            expression=path,
     778        ),
     779        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
     780            exp.JSONBContains,
     781            this=this,
     782            expression=key,
     783        ),
     784    }
     785
     786    EXPRESSION_PARSERS = {
     787        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
     788        exp.Column: lambda self: self._parse_column(),
     789        exp.Condition: lambda self: self._parse_assignment(),
     790        exp.DataType: lambda self: self._parse_types(allow_identifiers=False, schema=True),
     791        exp.Expression: lambda self: self._parse_expression(),
     792        exp.From: lambda self: self._parse_from(joins=True),
     793        exp.Group: lambda self: self._parse_group(),
     794        exp.Having: lambda self: self._parse_having(),
     795        exp.Hint: lambda self: self._parse_hint_body(),
     796        exp.Identifier: lambda self: self._parse_id_var(),
     797        exp.Join: lambda self: self._parse_join(),
     798        exp.Lambda: lambda self: self._parse_lambda(),
     799        exp.Lateral: lambda self: self._parse_lateral(),
     800        exp.Limit: lambda self: self._parse_limit(),
     801        exp.Offset: lambda self: self._parse_offset(),
     802        exp.Order: lambda self: self._parse_order(),
     803        exp.Ordered: lambda self: self._parse_ordered(),
     804        exp.Properties: lambda self: self._parse_properties(),
     805        exp.PartitionedByProperty: lambda self: self._parse_partitioned_by(),
     806        exp.Qualify: lambda self: self._parse_qualify(),
     807        exp.Returning: lambda self: self._parse_returning(),
     808        exp.Select: lambda self: self._parse_select(),
     809        exp.Sort: lambda self: self._parse_sort(exp.Sort, TokenType.SORT_BY),
     810        exp.Table: lambda self: self._parse_table_parts(),
     811        exp.TableAlias: lambda self: self._parse_table_alias(),
     812        exp.Tuple: lambda self: self._parse_value(values=False),
     813        exp.Whens: lambda self: self._parse_when_matched(),
     814        exp.Where: lambda self: self._parse_where(),
     815        exp.Window: lambda self: self._parse_named_window(),
     816        exp.With: lambda self: self._parse_with(),
     817        "JOIN_TYPE": lambda self: self._parse_join_parts(),
     818    }
     819
     820    STATEMENT_PARSERS = {
     821        TokenType.ALTER: lambda self: self._parse_alter(),
     822        TokenType.ANALYZE: lambda self: self._parse_analyze(),
     823        TokenType.BEGIN: lambda self: self._parse_transaction(),
     824        TokenType.CACHE: lambda self: self._parse_cache(),
     825        TokenType.COMMENT: lambda self: self._parse_comment(),
     826        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
     827        TokenType.COPY: lambda self: self._parse_copy(),
     828        TokenType.CREATE: lambda self: self._parse_create(),
     829        TokenType.DELETE: lambda self: self._parse_delete(),
     830        TokenType.DESC: lambda self: self._parse_describe(),
     831        TokenType.DESCRIBE: lambda self: self._parse_describe(),
     832        TokenType.DROP: lambda self: self._parse_drop(),
     833        TokenType.GRANT: lambda self: self._parse_grant(),
     834        TokenType.INSERT: lambda self: self._parse_insert(),
     835        TokenType.KILL: lambda self: self._parse_kill(),
     836        TokenType.LOAD: lambda self: self._parse_load(),
     837        TokenType.MERGE: lambda self: self._parse_merge(),
     838        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
     839        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
     840        TokenType.REFRESH: lambda self: self._parse_refresh(),
     841        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
     842        TokenType.SET: lambda self: self._parse_set(),
     843        TokenType.TRUNCATE: lambda self: self._parse_truncate_table(),
     844        TokenType.UNCACHE: lambda self: self._parse_uncache(),
     845        TokenType.UNPIVOT: lambda self: self._parse_simplified_pivot(is_unpivot=True),
     846        TokenType.UPDATE: lambda self: self._parse_update(),
     847        TokenType.USE: lambda self: self._parse_use(),
     848        TokenType.SEMICOLON: lambda self: exp.Semicolon(),
     849    }
     850
     851    UNARY_PARSERS = {
     852        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
     853        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
     854        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
     855        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
     856        TokenType.PIPE_SLASH: lambda self: self.expression(exp.Sqrt, this=self._parse_unary()),
     857        TokenType.DPIPE_SLASH: lambda self: self.expression(exp.Cbrt, this=self._parse_unary()),
     858    }
     859
     860    STRING_PARSERS = {
     861        TokenType.HEREDOC_STRING: lambda self, token: self.expression(
     862            exp.RawString, this=token.text
     863        ),
     864        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
     865            exp.National, this=token.text
     866        ),
     867        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
     868        TokenType.STRING: lambda self, token: self.expression(
     869            exp.Literal, this=token.text, is_string=True
     870        ),
     871        TokenType.UNICODE_STRING: lambda self, token: self.expression(
     872            exp.UnicodeString,
     873            this=token.text,
     874            escape=self._match_text_seq("UESCAPE") and self._parse_string(),
     875        ),
     876    }
     877
     878    NUMERIC_PARSERS = {
     879        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
     880        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
     881        TokenType.HEX_STRING: lambda self, token: self.expression(
     882            exp.HexString,
     883            this=token.text,
     884            is_integer=self.dialect.HEX_STRING_IS_INTEGER_TYPE or None,
     885        ),
     886        TokenType.NUMBER: lambda self, token: self.expression(
     887            exp.Literal, this=token.text, is_string=False
     888        ),
     889    }
     890
     891    PRIMARY_PARSERS = {
     892        **STRING_PARSERS,
     893        **NUMERIC_PARSERS,
     894        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
     895        TokenType.NULL: lambda self, _: self.expression(exp.Null),
     896        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
     897        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
     898        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
     899        TokenType.STAR: lambda self, _: self._parse_star_ops(),
     900    }
     901
     902    PLACEHOLDER_PARSERS = {
     903        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
     904        TokenType.PARAMETER: lambda self: self._parse_parameter(),
     905        TokenType.COLON: lambda self: (
     906            self.expression(exp.Placeholder, this=self._prev.text)
     907            if self._match_set(self.COLON_PLACEHOLDER_TOKENS)
     908            else None
     909        ),
     910    }
     911
     912    RANGE_PARSERS = {
     913        TokenType.AT_GT: binary_range_parser(exp.ArrayContainsAll),
     914        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
     915        TokenType.GLOB: binary_range_parser(exp.Glob),
     916        TokenType.ILIKE: binary_range_parser(exp.ILike),
     917        TokenType.IN: lambda self, this: self._parse_in(this),
     918        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
     919        TokenType.IS: lambda self, this: self._parse_is(this),
     920        TokenType.LIKE: binary_range_parser(exp.Like),
     921        TokenType.LT_AT: binary_range_parser(exp.ArrayContainsAll, reverse_args=True),
     922        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
     923        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
     924        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
     925        TokenType.FOR: lambda self, this: self._parse_comprehension(this),
     926    }
     927
     928    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
     929        "ALLOWED_VALUES": lambda self: self.expression(
     930            exp.AllowedValuesProperty, expressions=self._parse_csv(self._parse_primary)
     931        ),
     932        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
     933        "AUTO": lambda self: self._parse_auto_property(),
     934        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
     935        "BACKUP": lambda self: self.expression(
     936            exp.BackupProperty, this=self._parse_var(any_token=True)
     937        ),
     938        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
     939        "CHARSET": lambda self, **kwargs: self._parse_character_set(**kwargs),
     940        "CHARACTER SET": lambda self, **kwargs: self._parse_character_set(**kwargs),
     941        "CHECKSUM": lambda self: self._parse_checksum(),
     942        "CLUSTER BY": lambda self: self._parse_cluster(),
     943        "CLUSTERED": lambda self: self._parse_clustered_by(),
     944        "COLLATE": lambda self, **kwargs: self._parse_property_assignment(
     945            exp.CollateProperty, **kwargs
     946        ),
     947        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
     948        "CONTAINS": lambda self: self._parse_contains_property(),
     949        "COPY": lambda self: self._parse_copy_property(),
     950        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
     951        "DATA_DELETION": lambda self: self._parse_data_deletion_property(),
     952        "DEFINER": lambda self: self._parse_definer(),
     953        "DETERMINISTIC": lambda self: self.expression(
     954            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
     955        ),
     956        "DISTRIBUTED": lambda self: self._parse_distributed_property(),
     957        "DUPLICATE": lambda self: self._parse_composite_key_property(exp.DuplicateKeyProperty),
     958        "DYNAMIC": lambda self: self.expression(exp.DynamicProperty),
     959        "DISTKEY": lambda self: self._parse_distkey(),
     960        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
     961        "EMPTY": lambda self: self.expression(exp.EmptyProperty),
     962        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
     963        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
     964        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
     965        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
     966        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
     967        "FREESPACE": lambda self: self._parse_freespace(),
     968        "GLOBAL": lambda self: self.expression(exp.GlobalProperty),
     969        "HEAP": lambda self: self.expression(exp.HeapProperty),
     970        "ICEBERG": lambda self: self.expression(exp.IcebergProperty),
     971        "IMMUTABLE": lambda self: self.expression(
     972            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
     973        ),
     974        "INHERITS": lambda self: self.expression(
     975            exp.InheritsProperty, expressions=self._parse_wrapped_csv(self._parse_table)
     976        ),
     977        "INPUT": lambda self: self.expression(exp.InputModelProperty, this=self._parse_schema()),
     978        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
     979        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
     980        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
     981        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
     982        "LIKE": lambda self: self._parse_create_like(),
     983        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
     984        "LOCK": lambda self: self._parse_locking(),
     985        "LOCKING": lambda self: self._parse_locking(),
     986        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
     987        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
     988        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
     989        "MODIFIES": lambda self: self._parse_modifies_property(),
     990        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
     991        "NO": lambda self: self._parse_no_property(),
     992        "ON": lambda self: self._parse_on_property(),
     993        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
     994        "OUTPUT": lambda self: self.expression(exp.OutputModelProperty, this=self._parse_schema()),
     995        "PARTITION": lambda self: self._parse_partitioned_of(),
     996        "PARTITION BY": lambda self: self._parse_partitioned_by(),
     997        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
     998        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
     999        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
    1000        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
    1001        "READS": lambda self: self._parse_reads_property(),
    1002        "REMOTE": lambda self: self._parse_remote_with_connection(),
    1003        "RETURNS": lambda self: self._parse_returns(),
    1004        "STRICT": lambda self: self.expression(exp.StrictProperty),
    1005        "STREAMING": lambda self: self.expression(exp.StreamingTableProperty),
    1006        "ROW": lambda self: self._parse_row(),
    1007        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
    1008        "SAMPLE": lambda self: self.expression(
    1009            exp.SampleProperty, this=self._match_text_seq("BY") and self._parse_bitwise()
    1010        ),
    1011        "SECURE": lambda self: self.expression(exp.SecureProperty),
    1012        "SECURITY": lambda self: self._parse_security(),
    1013        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
    1014        "SETTINGS": lambda self: self._parse_settings_property(),
    1015        "SHARING": lambda self: self._parse_property_assignment(exp.SharingProperty),
    1016        "SORTKEY": lambda self: self._parse_sortkey(),
    1017        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
    1018        "STABLE": lambda self: self.expression(
    1019            exp.StabilityProperty, this=exp.Literal.string("STABLE")
    1020        ),
    1021        "STORED": lambda self: self._parse_stored(),
    1022        "SYSTEM_VERSIONING": lambda self: self._parse_system_versioning_property(),
    1023        "TBLPROPERTIES": lambda self: self._parse_wrapped_properties(),
    1024        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
    1025        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
    1026        "TO": lambda self: self._parse_to_table(),
    1027        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
    1028        "TRANSFORM": lambda self: self.expression(
    1029            exp.TransformModelProperty, expressions=self._parse_wrapped_csv(self._parse_expression)
    1030        ),
    1031        "TTL": lambda self: self._parse_ttl(),
    1032        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
    1033        "UNLOGGED": lambda self: self.expression(exp.UnloggedProperty),
    1034        "VOLATILE": lambda self: self._parse_volatile_property(),
    1035        "WITH": lambda self: self._parse_with_property(),
    1036    }
    1037
    1038    CONSTRAINT_PARSERS = {
    1039        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
    1040        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
    1041        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
    1042        "CHARACTER SET": lambda self: self.expression(
    1043            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
    1044        ),
    1045        "CHECK": lambda self: self.expression(
    1046            exp.CheckColumnConstraint,
    1047            this=self._parse_wrapped(self._parse_assignment),
    1048            enforced=self._match_text_seq("ENFORCED"),
    1049        ),
    1050        "COLLATE": lambda self: self.expression(
    1051            exp.CollateColumnConstraint,
    1052            this=self._parse_identifier() or self._parse_column(),
    1053        ),
    1054        "COMMENT": lambda self: self.expression(
    1055            exp.CommentColumnConstraint, this=self._parse_string()
    1056        ),
    1057        "COMPRESS": lambda self: self._parse_compress(),
    1058        "CLUSTERED": lambda self: self.expression(
    1059            exp.ClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
    1060        ),
    1061        "NONCLUSTERED": lambda self: self.expression(
    1062            exp.NonClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
    1063        ),
    1064        "DEFAULT": lambda self: self.expression(
    1065            exp.DefaultColumnConstraint, this=self._parse_bitwise()
    1066        ),
    1067        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
    1068        "EPHEMERAL": lambda self: self.expression(
    1069            exp.EphemeralColumnConstraint, this=self._parse_bitwise()
    1070        ),
    1071        "EXCLUDE": lambda self: self.expression(
    1072            exp.ExcludeColumnConstraint, this=self._parse_index_params()
    1073        ),
    1074        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
    1075        "FORMAT": lambda self: self.expression(
    1076            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
    1077        ),
    1078        "GENERATED": lambda self: self._parse_generated_as_identity(),
    1079        "IDENTITY": lambda self: self._parse_auto_increment(),
    1080        "INLINE": lambda self: self._parse_inline(),
    1081        "LIKE": lambda self: self._parse_create_like(),
    1082        "NOT": lambda self: self._parse_not_constraint(),
    1083        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
    1084        "ON": lambda self: (
    1085            self._match(TokenType.UPDATE)
    1086            and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function())
    1087        )
    1088        or self.expression(exp.OnProperty, this=self._parse_id_var()),
    1089        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
    1090        "PERIOD": lambda self: self._parse_period_for_system_time(),
    1091        "PRIMARY KEY": lambda self: self._parse_primary_key(),
    1092        "REFERENCES": lambda self: self._parse_references(match=False),
    1093        "TITLE": lambda self: self.expression(
    1094            exp.TitleColumnConstraint, this=self._parse_var_or_string()
    1095        ),
    1096        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
    1097        "UNIQUE": lambda self: self._parse_unique(),
    1098        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
    1099        "WATERMARK": lambda self: self.expression(
    1100            exp.WatermarkColumnConstraint,
    1101            this=self._match(TokenType.FOR) and self._parse_column(),
    1102            expression=self._match(TokenType.ALIAS) and self._parse_disjunction(),
    1103        ),
    1104        "WITH": lambda self: self.expression(
    1105            exp.Properties, expressions=self._parse_wrapped_properties()
    1106        ),
    1107        "BUCKET": lambda self: self._parse_partitioned_by_bucket_or_truncate(),
    1108        "TRUNCATE": lambda self: self._parse_partitioned_by_bucket_or_truncate(),
    1109    }
    1110
    1111    def _parse_partitioned_by_bucket_or_truncate(self) -> exp.Expression:
    1112        klass = (
    1113            exp.PartitionedByBucket
    1114            if self._prev.text.upper() == "BUCKET"
    1115            else exp.PartitionByTruncate
    1116        )
    1117
    1118        args = self._parse_wrapped_csv(lambda: self._parse_primary() or self._parse_column())
    1119        this, expression = seq_get(args, 0), seq_get(args, 1)
    1120
    1121        if isinstance(this, exp.Literal):
    1122            # Check for Iceberg partition transforms (bucket / truncate) and ensure their arguments are in the right order
    1123            #  - For Hive, it's `bucket(<num buckets>, <col name>)` or `truncate(<num_chars>, <col_name>)`
    1124            #  - For Trino, it's reversed - `bucket(<col name>, <num buckets>)` or `truncate(<col_name>, <num_chars>)`
    1125            # Both variants are canonicalized in the latter i.e `bucket(<col name>, <num buckets>)`
    1126            #
    1127            # Hive ref: https://docs.aws.amazon.com/athena/latest/ug/querying-iceberg-creating-tables.html#querying-iceberg-partitioning
    1128            # Trino ref: https://docs.aws.amazon.com/athena/latest/ug/create-table-as.html#ctas-table-properties
    1129            this, expression = expression, this
    1130
    1131        return self.expression(klass, this=this, expression=expression)
    1132
    1133    ALTER_PARSERS = {
    1134        "ADD": lambda self: self._parse_alter_table_add(),
    1135        "AS": lambda self: self._parse_select(),
    1136        "ALTER": lambda self: self._parse_alter_table_alter(),
    1137        "CLUSTER BY": lambda self: self._parse_cluster(wrapped=True),
    1138        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
    1139        "DROP": lambda self: self._parse_alter_table_drop(),
    1140        "RENAME": lambda self: self._parse_alter_table_rename(),
    1141        "SET": lambda self: self._parse_alter_table_set(),
    1142        "SWAP": lambda self: self.expression(
    1143            exp.SwapTable, this=self._match(TokenType.WITH) and self._parse_table(schema=True)
    1144        ),
    1145    }
    1146
    1147    ALTER_ALTER_PARSERS = {
    1148        "DISTKEY": lambda self: self._parse_alter_diststyle(),
    1149        "DISTSTYLE": lambda self: self._parse_alter_diststyle(),
    1150        "SORTKEY": lambda self: self._parse_alter_sortkey(),
    1151        "COMPOUND": lambda self: self._parse_alter_sortkey(compound=True),
    1152    }
    1153
    1154    SCHEMA_UNNAMED_CONSTRAINTS = {
    1155        "CHECK",
    1156        "EXCLUDE",
    1157        "FOREIGN KEY",
    1158        "LIKE",
    1159        "PERIOD",
    1160        "PRIMARY KEY",
    1161        "UNIQUE",
    1162        "WATERMARK",
    1163        "BUCKET",
    1164        "TRUNCATE",
    1165    }
    1166
    1167    NO_PAREN_FUNCTION_PARSERS = {
    1168        "ANY": lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
    1169        "CASE": lambda self: self._parse_case(),
    1170        "CONNECT_BY_ROOT": lambda self: self.expression(
    1171            exp.ConnectByRoot, this=self._parse_column()
    1172        ),
    1173        "IF": lambda self: self._parse_if(),
    1174    }
    1175
    1176    INVALID_FUNC_NAME_TOKENS = {
    1177        TokenType.IDENTIFIER,
    1178        TokenType.STRING,
    1179    }
    1180
    1181    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
    1182
    1183    KEY_VALUE_DEFINITIONS = (exp.Alias, exp.EQ, exp.PropertyEQ, exp.Slice)
    1184
    1185    FUNCTION_PARSERS = {
    1186        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
    1187        "CEIL": lambda self: self._parse_ceil_floor(exp.Ceil),
    1188        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
    1189        "DECODE": lambda self: self._parse_decode(),
    1190        "EXTRACT": lambda self: self._parse_extract(),
    1191        "FLOOR": lambda self: self._parse_ceil_floor(exp.Floor),
    1192        "GAP_FILL": lambda self: self._parse_gap_fill(),
    1193        "JSON_OBJECT": lambda self: self._parse_json_object(),
    1194        "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
    1195        "JSON_TABLE": lambda self: self._parse_json_table(),
    1196        "MATCH": lambda self: self._parse_match_against(),
    1197        "NORMALIZE": lambda self: self._parse_normalize(),
    1198        "OPENJSON": lambda self: self._parse_open_json(),
    1199        "OVERLAY": lambda self: self._parse_overlay(),
    1200        "POSITION": lambda self: self._parse_position(),
    1201        "PREDICT": lambda self: self._parse_predict(),
    1202        "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
    1203        "STRING_AGG": lambda self: self._parse_string_agg(),
    1204        "SUBSTRING": lambda self: self._parse_substring(),
    1205        "TRIM": lambda self: self._parse_trim(),
    1206        "TRY_CAST": lambda self: self._parse_cast(False, safe=True),
    1207        "TRY_CONVERT": lambda self: self._parse_convert(False, safe=True),
    1208        "XMLELEMENT": lambda self: self.expression(
    1209            exp.XMLElement,
    1210            this=self._match_text_seq("NAME") and self._parse_id_var(),
    1211            expressions=self._match(TokenType.COMMA) and self._parse_csv(self._parse_expression),
    1212        ),
    1213        "XMLTABLE": lambda self: self._parse_xml_table(),
    1214    }
    1215
    1216    QUERY_MODIFIER_PARSERS = {
    1217        TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
    1218        TokenType.PREWHERE: lambda self: ("prewhere", self._parse_prewhere()),
    1219        TokenType.WHERE: lambda self: ("where", self._parse_where()),
    1220        TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
    1221        TokenType.HAVING: lambda self: ("having", self._parse_having()),
    1222        TokenType.QUALIFY: lambda self: ("qualify", self._parse_qualify()),
    1223        TokenType.WINDOW: lambda self: ("windows", self._parse_window_clause()),
    1224        TokenType.ORDER_BY: lambda self: ("order", self._parse_order()),
    1225        TokenType.LIMIT: lambda self: ("limit", self._parse_limit()),
    1226        TokenType.FETCH: lambda self: ("limit", self._parse_limit()),
    1227        TokenType.OFFSET: lambda self: ("offset", self._parse_offset()),
    1228        TokenType.FOR: lambda self: ("locks", self._parse_locks()),
    1229        TokenType.LOCK: lambda self: ("locks", self._parse_locks()),
    1230        TokenType.TABLE_SAMPLE: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
    1231        TokenType.USING: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
    1232        TokenType.CLUSTER_BY: lambda self: (
    1233            "cluster",
    1234            self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
    1235        ),
    1236        TokenType.DISTRIBUTE_BY: lambda self: (
    1237            "distribute",
    1238            self._parse_sort(exp.Distribute, TokenType.DISTRIBUTE_BY),
    1239        ),
    1240        TokenType.SORT_BY: lambda self: ("sort", self._parse_sort(exp.Sort, TokenType.SORT_BY)),
    1241        TokenType.CONNECT_BY: lambda self: ("connect", self._parse_connect(skip_start_token=True)),
    1242        TokenType.START_WITH: lambda self: ("connect", self._parse_connect()),
    1243    }
    1244
    1245    SET_PARSERS = {
    1246        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
    1247        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
    1248        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
    1249        "TRANSACTION": lambda self: self._parse_set_transaction(),
    1250    }
    1251
    1252    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
    1253
    1254    TYPE_LITERAL_PARSERS = {
    1255        exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
    1256    }
    1257
    1258    TYPE_CONVERTERS: t.Dict[exp.DataType.Type, t.Callable[[exp.DataType], exp.DataType]] = {}
    1259
    1260    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
    1261
    1262    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
    1263
    1264    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
    1265    TRANSACTION_CHARACTERISTICS: OPTIONS_TYPE = {
    1266        "ISOLATION": (
    1267            ("LEVEL", "REPEATABLE", "READ"),
    1268            ("LEVEL", "READ", "COMMITTED"),
    1269            ("LEVEL", "READ", "UNCOMITTED"),
    1270            ("LEVEL", "SERIALIZABLE"),
    1271        ),
    1272        "READ": ("WRITE", "ONLY"),
    1273    }
    1274
    1275    CONFLICT_ACTIONS: OPTIONS_TYPE = dict.fromkeys(
    1276        ("ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK", "UPDATE"), tuple()
    1277    )
    1278    CONFLICT_ACTIONS["DO"] = ("NOTHING", "UPDATE")
    1279
    1280    CREATE_SEQUENCE: OPTIONS_TYPE = {
    1281        "SCALE": ("EXTEND", "NOEXTEND"),
    1282        "SHARD": ("EXTEND", "NOEXTEND"),
    1283        "NO": ("CYCLE", "CACHE", "MAXVALUE", "MINVALUE"),
    1284        **dict.fromkeys(
    1285            (
    1286                "SESSION",
    1287                "GLOBAL",
    1288                "KEEP",
    1289                "NOKEEP",
    1290                "ORDER",
    1291                "NOORDER",
    1292                "NOCACHE",
    1293                "CYCLE",
    1294                "NOCYCLE",
    1295                "NOMINVALUE",
    1296                "NOMAXVALUE",
    1297                "NOSCALE",
    1298                "NOSHARD",
    1299            ),
    1300            tuple(),
    1301        ),
    1302    }
    1303
    1304    ISOLATED_LOADING_OPTIONS: OPTIONS_TYPE = {"FOR": ("ALL", "INSERT", "NONE")}
    1305
    1306    USABLES: OPTIONS_TYPE = dict.fromkeys(
    1307        ("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA", "CATALOG"), tuple()
    1308    )
    1309
    1310    CAST_ACTIONS: OPTIONS_TYPE = dict.fromkeys(("RENAME", "ADD"), ("FIELDS",))
    1311
    1312    SCHEMA_BINDING_OPTIONS: OPTIONS_TYPE = {
    1313        "TYPE": ("EVOLUTION",),
    1314        **dict.fromkeys(("BINDING", "COMPENSATION", "EVOLUTION"), tuple()),
    1315    }
    1316
    1317    PROCEDURE_OPTIONS: OPTIONS_TYPE = {}
    1318
    1319    EXECUTE_AS_OPTIONS: OPTIONS_TYPE = dict.fromkeys(("CALLER", "SELF", "OWNER"), tuple())
    1320
    1321    KEY_CONSTRAINT_OPTIONS: OPTIONS_TYPE = {
    1322        "NOT": ("ENFORCED",),
    1323        "MATCH": (
    1324            "FULL",
    1325            "PARTIAL",
    1326            "SIMPLE",
    1327        ),
    1328        "INITIALLY": ("DEFERRED", "IMMEDIATE"),
    1329        "USING": (
    1330            "BTREE",
    1331            "HASH",
    1332        ),
    1333        **dict.fromkeys(("DEFERRABLE", "NORELY", "RELY"), tuple()),
    1334    }
    1335
    1336    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
    1337
    1338    CLONE_KEYWORDS = {"CLONE", "COPY"}
    1339    HISTORICAL_DATA_PREFIX = {"AT", "BEFORE", "END"}
    1340    HISTORICAL_DATA_KIND = {"TIMESTAMP", "OFFSET", "STATEMENT", "STREAM"}
    1341
    1342    OPCLASS_FOLLOW_KEYWORDS = {"ASC", "DESC", "NULLS", "WITH"}
    1343
    1344    OPTYPE_FOLLOW_TOKENS = {TokenType.COMMA, TokenType.R_PAREN}
    1345
    1346    TABLE_INDEX_HINT_TOKENS = {TokenType.FORCE, TokenType.IGNORE, TokenType.USE}
    1347
    1348    VIEW_ATTRIBUTES = {"ENCRYPTION", "SCHEMABINDING", "VIEW_METADATA"}
    1349
    1350    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
    1351    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
    1352    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
    1353
    1354    JSON_KEY_VALUE_SEPARATOR_TOKENS = {TokenType.COLON, TokenType.COMMA, TokenType.IS}
    1355
    1356    FETCH_TOKENS = ID_VAR_TOKENS - {TokenType.ROW, TokenType.ROWS, TokenType.PERCENT}
    1357
    1358    ADD_CONSTRAINT_TOKENS = {
    1359        TokenType.CONSTRAINT,
    1360        TokenType.FOREIGN_KEY,
    1361        TokenType.INDEX,
    1362        TokenType.KEY,
    1363        TokenType.PRIMARY_KEY,
    1364        TokenType.UNIQUE,
    1365    }
    1366
    1367    DISTINCT_TOKENS = {TokenType.DISTINCT}
    1368
    1369    NULL_TOKENS = {TokenType.NULL}
    1370
    1371    UNNEST_OFFSET_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - SET_OPERATIONS
    1372
    1373    SELECT_START_TOKENS = {TokenType.L_PAREN, TokenType.WITH, TokenType.SELECT}
    1374
    1375    COPY_INTO_VARLEN_OPTIONS = {"FILE_FORMAT", "COPY_OPTIONS", "FORMAT_OPTIONS", "CREDENTIAL"}
    1376
    1377    IS_JSON_PREDICATE_KIND = {"VALUE", "SCALAR", "ARRAY", "OBJECT"}
    1378
    1379    ODBC_DATETIME_LITERALS = {
    1380        "d": exp.Date,
    1381        "t": exp.Time,
    1382        "ts": exp.Timestamp,
    1383    }
    1384
    1385    ON_CONDITION_TOKENS = {"ERROR", "NULL", "TRUE", "FALSE", "EMPTY"}
    1386
    1387    PRIVILEGE_FOLLOW_TOKENS = {TokenType.ON, TokenType.COMMA, TokenType.L_PAREN}
    1388
    1389    # The style options for the DESCRIBE statement
    1390    DESCRIBE_STYLES = {"ANALYZE", "EXTENDED", "FORMATTED", "HISTORY"}
    1391
    1392    # The style options for the ANALYZE statement
    1393    ANALYZE_STYLES = {
    1394        "BUFFER_USAGE_LIMIT",
    1395        "FULL",
    1396        "LOCAL",
    1397        "NO_WRITE_TO_BINLOG",
    1398        "SAMPLE",
    1399        "SKIP_LOCKED",
    1400        "VERBOSE",
    1401    }
    1402
    1403    ANALYZE_EXPRESSION_PARSERS = {
    1404        "ALL": lambda self: self._parse_analyze_columns(),
    1405        "COMPUTE": lambda self: self._parse_analyze_statistics(),
    1406        "DELETE": lambda self: self._parse_analyze_delete(),
    1407        "DROP": lambda self: self._parse_analyze_histogram(),
    1408        "ESTIMATE": lambda self: self._parse_analyze_statistics(),
    1409        "LIST": lambda self: self._parse_analyze_list(),
    1410        "PREDICATE": lambda self: self._parse_analyze_columns(),
    1411        "UPDATE": lambda self: self._parse_analyze_histogram(),
    1412        "VALIDATE": lambda self: self._parse_analyze_validate(),
    1413    }
    1414
    1415    PARTITION_KEYWORDS = {"PARTITION", "SUBPARTITION"}
    1416
    1417    AMBIGUOUS_ALIAS_TOKENS = (TokenType.LIMIT, TokenType.OFFSET)
    1418
    1419    OPERATION_MODIFIERS: t.Set[str] = set()
    1420
    1421    RECURSIVE_CTE_SEARCH_KIND = {"BREADTH", "DEPTH", "CYCLE"}
    1422
    1423    MODIFIABLES = (exp.Query, exp.Table, exp.TableFromRows)
    1424
    1425    STRICT_CAST = True
    1426
    1427    PREFIXED_PIVOT_COLUMNS = False
    1428    IDENTIFY_PIVOT_STRINGS = False
    1429
    1430    LOG_DEFAULTS_TO_LN = False
    1431
    1432    # Whether ADD is present for each column added by ALTER TABLE
    1433    ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
    1434
    1435    # Whether the table sample clause expects CSV syntax
    1436    TABLESAMPLE_CSV = False
    1437
    1438    # The default method used for table sampling
    1439    DEFAULT_SAMPLING_METHOD: t.Optional[str] = None
    1440
    1441    # Whether the SET command needs a delimiter (e.g. "=") for assignments
    1442    SET_REQUIRES_ASSIGNMENT_DELIMITER = True
    1443
    1444    # Whether the TRIM function expects the characters to trim as its first argument
    1445    TRIM_PATTERN_FIRST = False
    1446
    1447    # Whether string aliases are supported `SELECT COUNT(*) 'count'`
    1448    STRING_ALIASES = False
    1449
    1450    # Whether query modifiers such as LIMIT are attached to the UNION node (vs its right operand)
    1451    MODIFIERS_ATTACHED_TO_SET_OP = True
    1452    SET_OP_MODIFIERS = {"order", "limit", "offset"}
    1453
    1454    # Whether to parse IF statements that aren't followed by a left parenthesis as commands
    1455    NO_PAREN_IF_COMMANDS = True
    1456
    1457    # Whether the -> and ->> operators expect documents of type JSON (e.g. Postgres)
    1458    JSON_ARROWS_REQUIRE_JSON_TYPE = False
    1459
    1460    # Whether the `:` operator is used to extract a value from a VARIANT column
    1461    COLON_IS_VARIANT_EXTRACT = False
    1462
    1463    # Whether or not a VALUES keyword needs to be followed by '(' to form a VALUES clause.
    1464    # If this is True and '(' is not found, the keyword will be treated as an identifier
    1465    VALUES_FOLLOWED_BY_PAREN = True
    1466
    1467    # Whether implicit unnesting is supported, e.g. SELECT 1 FROM y.z AS z, z.a (Redshift)
    1468    SUPPORTS_IMPLICIT_UNNEST = False
    1469
    1470    # Whether or not interval spans are supported, INTERVAL 1 YEAR TO MONTHS
    1471    INTERVAL_SPANS = True
    1472
    1473    # Whether a PARTITION clause can follow a table reference
    1474    SUPPORTS_PARTITION_SELECTION = False
    1475
    1476    # Whether the `name AS expr` schema/column constraint requires parentheses around `expr`
    1477    WRAPPED_TRANSFORM_COLUMN_CONSTRAINT = True
    1478
    1479    # Whether the 'AS' keyword is optional in the CTE definition syntax
    1480    OPTIONAL_ALIAS_TOKEN_CTE = True
    1481
    1482    __slots__ = (
    1483        "error_level",
    1484        "error_message_context",
    1485        "max_errors",
    1486        "dialect",
    1487        "sql",
    1488        "errors",
    1489        "_tokens",
    1490        "_index",
    1491        "_curr",
    1492        "_next",
    1493        "_prev",
    1494        "_prev_comments",
    1495    )
    1496
    1497    # Autofilled
    1498    SHOW_TRIE: t.Dict = {}
    1499    SET_TRIE: t.Dict = {}
    1500
    1501    def __init__(
    1502        self,
    1503        error_level: t.Optional[ErrorLevel] = None,
    1504        error_message_context: int = 100,
    1505        max_errors: int = 3,
    1506        dialect: DialectType = None,
    1507    ):
    1508        from sqlglot.dialects import Dialect
    1509
    1510        self.error_level = error_level or ErrorLevel.IMMEDIATE
    1511        self.error_message_context = error_message_context
    1512        self.max_errors = max_errors
    1513        self.dialect = Dialect.get_or_raise(dialect)
    1514        self.reset()
    1515
    1516    def reset(self):
    1517        self.sql = ""
    1518        self.errors = []
    1519        self._tokens = []
    1520        self._index = 0
    1521        self._curr = None
    1522        self._next = None
    1523        self._prev = None
    1524        self._prev_comments = None
    1525
    1526    def parse(
    1527        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    1528    ) -> t.List[t.Optional[exp.Expression]]:
    1529        """
    1530        Parses a list of tokens and returns a list of syntax trees, one tree
    1531        per parsed SQL statement.
    1532
    1533        Args:
    1534            raw_tokens: The list of tokens.
    1535            sql: The original SQL string, used to produce helpful debug messages.
    1536
    1537        Returns:
    1538            The list of the produced syntax trees.
    1539        """
    1540        return self._parse(
    1541            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    1542        )
    1543
    1544    def parse_into(
    1545        self,
    1546        expression_types: exp.IntoType,
    1547        raw_tokens: t.List[Token],
    1548        sql: t.Optional[str] = None,
    1549    ) -> t.List[t.Optional[exp.Expression]]:
    1550        """
    1551        Parses a list of tokens into a given Expression type. If a collection of Expression
    1552        types is given instead, this method will try to parse the token list into each one
    1553        of them, stopping at the first for which the parsing succeeds.
    1554
    1555        Args:
    1556            expression_types: The expression type(s) to try and parse the token list into.
    1557            raw_tokens: The list of tokens.
    1558            sql: The original SQL string, used to produce helpful debug messages.
    1559
    1560        Returns:
    1561            The target Expression.
    1562        """
    1563        errors = []
    1564        for expression_type in ensure_list(expression_types):
    1565            parser = self.EXPRESSION_PARSERS.get(expression_type)
    1566            if not parser:
    1567                raise TypeError(f"No parser registered for {expression_type}")
    1568
    1569            try:
    1570                return self._parse(parser, raw_tokens, sql)
    1571            except ParseError as e:
    1572                e.errors[0]["into_expression"] = expression_type
    1573                errors.append(e)
    1574
    1575        raise ParseError(
    1576            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    1577            errors=merge_errors(errors),
    1578        ) from errors[-1]
    1579
    1580    def _parse(
    1581        self,
    1582        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
    1583        raw_tokens: t.List[Token],
    1584        sql: t.Optional[str] = None,
    1585    ) -> t.List[t.Optional[exp.Expression]]:
    1586        self.reset()
    1587        self.sql = sql or ""
    1588
    1589        total = len(raw_tokens)
    1590        chunks: t.List[t.List[Token]] = [[]]
    1591
    1592        for i, token in enumerate(raw_tokens):
    1593            if token.token_type == TokenType.SEMICOLON:
    1594                if token.comments:
    1595                    chunks.append([token])
    1596
    1597                if i < total - 1:
    1598                    chunks.append([])
    1599            else:
    1600                chunks[-1].append(token)
    1601
    1602        expressions = []
    1603
    1604        for tokens in chunks:
    1605            self._index = -1
    1606            self._tokens = tokens
    1607            self._advance()
    1608
    1609            expressions.append(parse_method(self))
    1610
    1611            if self._index < len(self._tokens):
    1612                self.raise_error("Invalid expression / Unexpected token")
    1613
    1614            self.check_errors()
    1615
    1616        return expressions
    1617
    1618    def check_errors(self) -> None:
    1619        """Logs or raises any found errors, depending on the chosen error level setting."""
    1620        if self.error_level == ErrorLevel.WARN:
    1621            for error in self.errors:
    1622                logger.error(str(error))
    1623        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1624            raise ParseError(
    1625                concat_messages(self.errors, self.max_errors),
    1626                errors=merge_errors(self.errors),
    1627            )
    1628
    1629    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1630        """
    1631        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1632        error level setting.
    1633        """
    1634        token = token or self._curr or self._prev or Token.string("")
    1635        start = token.start
    1636        end = token.end + 1
    1637        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1638        highlight = self.sql[start:end]
    1639        end_context = self.sql[end : end + self.error_message_context]
    1640
    1641        error = ParseError.new(
    1642            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1643            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1644            description=message,
    1645            line=token.line,
    1646            col=token.col,
    1647            start_context=start_context,
    1648            highlight=highlight,
    1649            end_context=end_context,
    1650        )
    1651
    1652        if self.error_level == ErrorLevel.IMMEDIATE:
    1653            raise error
    1654
    1655        self.errors.append(error)
    1656
    1657    def expression(
    1658        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1659    ) -> E:
    1660        """
    1661        Creates a new, validated Expression.
    1662
    1663        Args:
    1664            exp_class: The expression class to instantiate.
    1665            comments: An optional list of comments to attach to the expression.
    1666            kwargs: The arguments to set for the expression along with their respective values.
    1667
    1668        Returns:
    1669            The target expression.
    1670        """
    1671        instance = exp_class(**kwargs)
    1672        instance.add_comments(comments) if comments else self._add_comments(instance)
    1673        return self.validate_expression(instance)
    1674
    1675    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
    1676        if expression and self._prev_comments:
    1677            expression.add_comments(self._prev_comments)
    1678            self._prev_comments = None
    1679
    1680    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1681        """
    1682        Validates an Expression, making sure that all its mandatory arguments are set.
    1683
    1684        Args:
    1685            expression: The expression to validate.
    1686            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1687
    1688        Returns:
    1689            The validated expression.
    1690        """
    1691        if self.error_level != ErrorLevel.IGNORE:
    1692            for error_message in expression.error_messages(args):
    1693                self.raise_error(error_message)
    1694
    1695        return expression
    1696
    1697    def _find_sql(self, start: Token, end: Token) -> str:
    1698        return self.sql[start.start : end.end + 1]
    1699
    1700    def _is_connected(self) -> bool:
    1701        return self._prev and self._curr and self._prev.end + 1 == self._curr.start
    1702
    1703    def _advance(self, times: int = 1) -> None:
    1704        self._index += times
    1705        self._curr = seq_get(self._tokens, self._index)
    1706        self._next = seq_get(self._tokens, self._index + 1)
    1707
    1708        if self._index > 0:
    1709            self._prev = self._tokens[self._index - 1]
    1710            self._prev_comments = self._prev.comments
    1711        else:
    1712            self._prev = None
    1713            self._prev_comments = None
    1714
    1715    def _retreat(self, index: int) -> None:
    1716        if index != self._index:
    1717            self._advance(index - self._index)
    1718
    1719    def _warn_unsupported(self) -> None:
    1720        if len(self._tokens) <= 1:
    1721            return
    1722
    1723        # We use _find_sql because self.sql may comprise multiple chunks, and we're only
    1724        # interested in emitting a warning for the one being currently processed.
    1725        sql = self._find_sql(self._tokens[0], self._tokens[-1])[: self.error_message_context]
    1726
    1727        logger.warning(
    1728            f"'{sql}' contains unsupported syntax. Falling back to parsing as a 'Command'."
    1729        )
    1730
    1731    def _parse_command(self) -> exp.Command:
    1732        self._warn_unsupported()
    1733        return self.expression(
    1734            exp.Command,
    1735            comments=self._prev_comments,
    1736            this=self._prev.text.upper(),
    1737            expression=self._parse_string(),
    1738        )
    1739
    1740    def _try_parse(self, parse_method: t.Callable[[], T], retreat: bool = False) -> t.Optional[T]:
    1741        """
    1742        Attemps to backtrack if a parse function that contains a try/catch internally raises an error.
    1743        This behavior can be different depending on the uset-set ErrorLevel, so _try_parse aims to
    1744        solve this by setting & resetting the parser state accordingly
    1745        """
    1746        index = self._index
    1747        error_level = self.error_level
    1748
    1749        self.error_level = ErrorLevel.IMMEDIATE
    1750        try:
    1751            this = parse_method()
    1752        except ParseError:
    1753            this = None
    1754        finally:
    1755            if not this or retreat:
    1756                self._retreat(index)
    1757            self.error_level = error_level
    1758
    1759        return this
    1760
    1761    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
    1762        start = self._prev
    1763        exists = self._parse_exists() if allow_exists else None
    1764
    1765        self._match(TokenType.ON)
    1766
    1767        materialized = self._match_text_seq("MATERIALIZED")
    1768        kind = self._match_set(self.CREATABLES) and self._prev
    1769        if not kind:
    1770            return self._parse_as_command(start)
    1771
    1772        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
    1773            this = self._parse_user_defined_function(kind=kind.token_type)
    1774        elif kind.token_type == TokenType.TABLE:
    1775            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
    1776        elif kind.token_type == TokenType.COLUMN:
    1777            this = self._parse_column()
    1778        else:
    1779            this = self._parse_id_var()
    1780
    1781        self._match(TokenType.IS)
    1782
    1783        return self.expression(
    1784            exp.Comment,
    1785            this=this,
    1786            kind=kind.text,
    1787            expression=self._parse_string(),
    1788            exists=exists,
    1789            materialized=materialized,
    1790        )
    1791
    1792    def _parse_to_table(
    1793        self,
    1794    ) -> exp.ToTableProperty:
    1795        table = self._parse_table_parts(schema=True)
    1796        return self.expression(exp.ToTableProperty, this=table)
    1797
    1798    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
    1799    def _parse_ttl(self) -> exp.Expression:
    1800        def _parse_ttl_action() -> t.Optional[exp.Expression]:
    1801            this = self._parse_bitwise()
    1802
    1803            if self._match_text_seq("DELETE"):
    1804                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
    1805            if self._match_text_seq("RECOMPRESS"):
    1806                return self.expression(
    1807                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
    1808                )
    1809            if self._match_text_seq("TO", "DISK"):
    1810                return self.expression(
    1811                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
    1812                )
    1813            if self._match_text_seq("TO", "VOLUME"):
    1814                return self.expression(
    1815                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
    1816                )
    1817
    1818            return this
    1819
    1820        expressions = self._parse_csv(_parse_ttl_action)
    1821        where = self._parse_where()
    1822        group = self._parse_group()
    1823
    1824        aggregates = None
    1825        if group and self._match(TokenType.SET):
    1826            aggregates = self._parse_csv(self._parse_set_item)
    1827
    1828        return self.expression(
    1829            exp.MergeTreeTTL,
    1830            expressions=expressions,
    1831            where=where,
    1832            group=group,
    1833            aggregates=aggregates,
    1834        )
    1835
    1836    def _parse_statement(self) -> t.Optional[exp.Expression]:
    1837        if self._curr is None:
    1838            return None
    1839
    1840        if self._match_set(self.STATEMENT_PARSERS):
    1841            comments = self._prev_comments
    1842            stmt = self.STATEMENT_PARSERS[self._prev.token_type](self)
    1843            stmt.add_comments(comments, prepend=True)
    1844            return stmt
    1845
    1846        if self._match_set(self.dialect.tokenizer.COMMANDS):
    1847            return self._parse_command()
    1848
    1849        expression = self._parse_expression()
    1850        expression = self._parse_set_operations(expression) if expression else self._parse_select()
    1851        return self._parse_query_modifiers(expression)
    1852
    1853    def _parse_drop(self, exists: bool = False) -> exp.Drop | exp.Command:
    1854        start = self._prev
    1855        temporary = self._match(TokenType.TEMPORARY)
    1856        materialized = self._match_text_seq("MATERIALIZED")
    1857
    1858        kind = self._match_set(self.CREATABLES) and self._prev.text.upper()
    1859        if not kind:
    1860            return self._parse_as_command(start)
    1861
    1862        concurrently = self._match_text_seq("CONCURRENTLY")
    1863        if_exists = exists or self._parse_exists()
    1864
    1865        if kind == "COLUMN":
    1866            this = self._parse_column()
    1867        else:
    1868            this = self._parse_table_parts(
    1869                schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
    1870            )
    1871
    1872        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
    1873
    1874        if self._match(TokenType.L_PAREN, advance=False):
    1875            expressions = self._parse_wrapped_csv(self._parse_types)
    1876        else:
    1877            expressions = None
    1878
    1879        return self.expression(
    1880            exp.Drop,
    1881            exists=if_exists,
    1882            this=this,
    1883            expressions=expressions,
    1884            kind=self.dialect.CREATABLE_KIND_MAPPING.get(kind) or kind,
    1885            temporary=temporary,
    1886            materialized=materialized,
    1887            cascade=self._match_text_seq("CASCADE"),
    1888            constraints=self._match_text_seq("CONSTRAINTS"),
    1889            purge=self._match_text_seq("PURGE"),
    1890            cluster=cluster,
    1891            concurrently=concurrently,
    1892        )
    1893
    1894    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
    1895        return (
    1896            self._match_text_seq("IF")
    1897            and (not not_ or self._match(TokenType.NOT))
    1898            and self._match(TokenType.EXISTS)
    1899        )
    1900
    1901    def _parse_create(self) -> exp.Create | exp.Command:
    1902        # Note: this can't be None because we've matched a statement parser
    1903        start = self._prev
    1904
    1905        replace = (
    1906            start.token_type == TokenType.REPLACE
    1907            or self._match_pair(TokenType.OR, TokenType.REPLACE)
    1908            or self._match_pair(TokenType.OR, TokenType.ALTER)
    1909        )
    1910        refresh = self._match_pair(TokenType.OR, TokenType.REFRESH)
    1911
    1912        unique = self._match(TokenType.UNIQUE)
    1913
    1914        if self._match_text_seq("CLUSTERED", "COLUMNSTORE"):
    1915            clustered = True
    1916        elif self._match_text_seq("NONCLUSTERED", "COLUMNSTORE") or self._match_text_seq(
    1917            "COLUMNSTORE"
    1918        ):
    1919            clustered = False
    1920        else:
    1921            clustered = None
    1922
    1923        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
    1924            self._advance()
    1925
    1926        properties = None
    1927        create_token = self._match_set(self.CREATABLES) and self._prev
    1928
    1929        if not create_token:
    1930            # exp.Properties.Location.POST_CREATE
    1931            properties = self._parse_properties()
    1932            create_token = self._match_set(self.CREATABLES) and self._prev
    1933
    1934            if not properties or not create_token:
    1935                return self._parse_as_command(start)
    1936
    1937        concurrently = self._match_text_seq("CONCURRENTLY")
    1938        exists = self._parse_exists(not_=True)
    1939        this = None
    1940        expression: t.Optional[exp.Expression] = None
    1941        indexes = None
    1942        no_schema_binding = None
    1943        begin = None
    1944        end = None
    1945        clone = None
    1946
    1947        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
    1948            nonlocal properties
    1949            if properties and temp_props:
    1950                properties.expressions.extend(temp_props.expressions)
    1951            elif temp_props:
    1952                properties = temp_props
    1953
    1954        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
    1955            this = self._parse_user_defined_function(kind=create_token.token_type)
    1956
    1957            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
    1958            extend_props(self._parse_properties())
    1959
    1960            expression = self._match(TokenType.ALIAS) and self._parse_heredoc()
    1961            extend_props(self._parse_properties())
    1962
    1963            if not expression:
    1964                if self._match(TokenType.COMMAND):
    1965                    expression = self._parse_as_command(self._prev)
    1966                else:
    1967                    begin = self._match(TokenType.BEGIN)
    1968                    return_ = self._match_text_seq("RETURN")
    1969
    1970                    if self._match(TokenType.STRING, advance=False):
    1971                        # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
    1972                        # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
    1973                        expression = self._parse_string()
    1974                        extend_props(self._parse_properties())
    1975                    else:
    1976                        expression = self._parse_user_defined_function_expression()
    1977
    1978                    end = self._match_text_seq("END")
    1979
    1980                    if return_:
    1981                        expression = self.expression(exp.Return, this=expression)
    1982        elif create_token.token_type == TokenType.INDEX:
    1983            # Postgres allows anonymous indexes, eg. CREATE INDEX IF NOT EXISTS ON t(c)
    1984            if not self._match(TokenType.ON):
    1985                index = self._parse_id_var()
    1986                anonymous = False
    1987            else:
    1988                index = None
    1989                anonymous = True
    1990
    1991            this = self._parse_index(index=index, anonymous=anonymous)
    1992        elif create_token.token_type in self.DB_CREATABLES:
    1993            table_parts = self._parse_table_parts(
    1994                schema=True, is_db_reference=create_token.token_type == TokenType.SCHEMA
    1995            )
    1996
    1997            # exp.Properties.Location.POST_NAME
    1998            self._match(TokenType.COMMA)
    1999            extend_props(self._parse_properties(before=True))
    2000
    2001            this = self._parse_schema(this=table_parts)
    2002
    2003            # exp.Properties.Location.POST_SCHEMA and POST_WITH
    2004            extend_props(self._parse_properties())
    2005
    2006            has_alias = self._match(TokenType.ALIAS)
    2007            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
    2008                # exp.Properties.Location.POST_ALIAS
    2009                extend_props(self._parse_properties())
    2010
    2011            if create_token.token_type == TokenType.SEQUENCE:
    2012                expression = self._parse_types()
    2013                extend_props(self._parse_properties())
    2014            else:
    2015                expression = self._parse_ddl_select()
    2016
    2017                # Some dialects also support using a table as an alias instead of a SELECT.
    2018                # Here we fallback to this as an alternative.
    2019                if not expression and has_alias:
    2020                    expression = self._try_parse(self._parse_table_parts)
    2021
    2022            if create_token.token_type == TokenType.TABLE:
    2023                # exp.Properties.Location.POST_EXPRESSION
    2024                extend_props(self._parse_properties())
    2025
    2026                indexes = []
    2027                while True:
    2028                    index = self._parse_index()
    2029
    2030                    # exp.Properties.Location.POST_INDEX
    2031                    extend_props(self._parse_properties())
    2032                    if not index:
    2033                        break
    2034                    else:
    2035                        self._match(TokenType.COMMA)
    2036                        indexes.append(index)
    2037            elif create_token.token_type == TokenType.VIEW:
    2038                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
    2039                    no_schema_binding = True
    2040            elif create_token.token_type in (TokenType.SINK, TokenType.SOURCE):
    2041                extend_props(self._parse_properties())
    2042
    2043            shallow = self._match_text_seq("SHALLOW")
    2044
    2045            if self._match_texts(self.CLONE_KEYWORDS):
    2046                copy = self._prev.text.lower() == "copy"
    2047                clone = self.expression(
    2048                    exp.Clone, this=self._parse_table(schema=True), shallow=shallow, copy=copy
    2049                )
    2050
    2051        if self._curr and not self._match_set((TokenType.R_PAREN, TokenType.COMMA), advance=False):
    2052            return self._parse_as_command(start)
    2053
    2054        create_kind_text = create_token.text.upper()
    2055        return self.expression(
    2056            exp.Create,
    2057            this=this,
    2058            kind=self.dialect.CREATABLE_KIND_MAPPING.get(create_kind_text) or create_kind_text,
    2059            replace=replace,
    2060            refresh=refresh,
    2061            unique=unique,
    2062            expression=expression,
    2063            exists=exists,
    2064            properties=properties,
    2065            indexes=indexes,
    2066            no_schema_binding=no_schema_binding,
    2067            begin=begin,
    2068            end=end,
    2069            clone=clone,
    2070            concurrently=concurrently,
    2071            clustered=clustered,
    2072        )
    2073
    2074    def _parse_sequence_properties(self) -> t.Optional[exp.SequenceProperties]:
    2075        seq = exp.SequenceProperties()
    2076
    2077        options = []
    2078        index = self._index
    2079
    2080        while self._curr:
    2081            self._match(TokenType.COMMA)
    2082            if self._match_text_seq("INCREMENT"):
    2083                self._match_text_seq("BY")
    2084                self._match_text_seq("=")
    2085                seq.set("increment", self._parse_term())
    2086            elif self._match_text_seq("MINVALUE"):
    2087                seq.set("minvalue", self._parse_term())
    2088            elif self._match_text_seq("MAXVALUE"):
    2089                seq.set("maxvalue", self._parse_term())
    2090            elif self._match(TokenType.START_WITH) or self._match_text_seq("START"):
    2091                self._match_text_seq("=")
    2092                seq.set("start", self._parse_term())
    2093            elif self._match_text_seq("CACHE"):
    2094                # T-SQL allows empty CACHE which is initialized dynamically
    2095                seq.set("cache", self._parse_number() or True)
    2096            elif self._match_text_seq("OWNED", "BY"):
    2097                # "OWNED BY NONE" is the default
    2098                seq.set("owned", None if self._match_text_seq("NONE") else self._parse_column())
    2099            else:
    2100                opt = self._parse_var_from_options(self.CREATE_SEQUENCE, raise_unmatched=False)
    2101                if opt:
    2102                    options.append(opt)
    2103                else:
    2104                    break
    2105
    2106        seq.set("options", options if options else None)
    2107        return None if self._index == index else seq
    2108
    2109    def _parse_property_before(self) -> t.Optional[exp.Expression]:
    2110        # only used for teradata currently
    2111        self._match(TokenType.COMMA)
    2112
    2113        kwargs = {
    2114            "no": self._match_text_seq("NO"),
    2115            "dual": self._match_text_seq("DUAL"),
    2116            "before": self._match_text_seq("BEFORE"),
    2117            "default": self._match_text_seq("DEFAULT"),
    2118            "local": (self._match_text_seq("LOCAL") and "LOCAL")
    2119            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
    2120            "after": self._match_text_seq("AFTER"),
    2121            "minimum": self._match_texts(("MIN", "MINIMUM")),
    2122            "maximum": self._match_texts(("MAX", "MAXIMUM")),
    2123        }
    2124
    2125        if self._match_texts(self.PROPERTY_PARSERS):
    2126            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
    2127            try:
    2128                return parser(self, **{k: v for k, v in kwargs.items() if v})
    2129            except TypeError:
    2130                self.raise_error(f"Cannot parse property '{self._prev.text}'")
    2131
    2132        return None
    2133
    2134    def _parse_wrapped_properties(self) -> t.List[exp.Expression]:
    2135        return self._parse_wrapped_csv(self._parse_property)
    2136
    2137    def _parse_property(self) -> t.Optional[exp.Expression]:
    2138        if self._match_texts(self.PROPERTY_PARSERS):
    2139            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
    2140
    2141        if self._match(TokenType.DEFAULT) and self._match_texts(self.PROPERTY_PARSERS):
    2142            return self.PROPERTY_PARSERS[self._prev.text.upper()](self, default=True)
    2143
    2144        if self._match_text_seq("COMPOUND", "SORTKEY"):
    2145            return self._parse_sortkey(compound=True)
    2146
    2147        if self._match_text_seq("SQL", "SECURITY"):
    2148            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
    2149
    2150        index = self._index
    2151        key = self._parse_column()
    2152
    2153        if not self._match(TokenType.EQ):
    2154            self._retreat(index)
    2155            return self._parse_sequence_properties()
    2156
    2157        # Transform the key to exp.Dot if it's dotted identifiers wrapped in exp.Column or to exp.Var otherwise
    2158        if isinstance(key, exp.Column):
    2159            key = key.to_dot() if len(key.parts) > 1 else exp.var(key.name)
    2160
    2161        value = self._parse_bitwise() or self._parse_var(any_token=True)
    2162
    2163        # Transform the value to exp.Var if it was parsed as exp.Column(exp.Identifier())
    2164        if isinstance(value, exp.Column):
    2165            value = exp.var(value.name)
    2166
    2167        return self.expression(exp.Property, this=key, value=value)
    2168
    2169    def _parse_stored(self) -> t.Union[exp.FileFormatProperty, exp.StorageHandlerProperty]:
    2170        if self._match_text_seq("BY"):
    2171            return self.expression(exp.StorageHandlerProperty, this=self._parse_var_or_string())
    2172
    2173        self._match(TokenType.ALIAS)
    2174        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
    2175        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
    2176
    2177        return self.expression(
    2178            exp.FileFormatProperty,
    2179            this=(
    2180                self.expression(
    2181                    exp.InputOutputFormat,
    2182                    input_format=input_format,
    2183                    output_format=output_format,
    2184                )
    2185                if input_format or output_format
    2186                else self._parse_var_or_string() or self._parse_number() or self._parse_id_var()
    2187            ),
    2188        )
    2189
    2190    def _parse_unquoted_field(self) -> t.Optional[exp.Expression]:
    2191        field = self._parse_field()
    2192        if isinstance(field, exp.Identifier) and not field.quoted:
    2193            field = exp.var(field)
    2194
    2195        return field
    2196
    2197    def _parse_property_assignment(self, exp_class: t.Type[E], **kwargs: t.Any) -> E:
    2198        self._match(TokenType.EQ)
    2199        self._match(TokenType.ALIAS)
    2200
    2201        return self.expression(exp_class, this=self._parse_unquoted_field(), **kwargs)
    2202
    2203    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
    2204        properties = []
    2205        while True:
    2206            if before:
    2207                prop = self._parse_property_before()
    2208            else:
    2209                prop = self._parse_property()
    2210            if not prop:
    2211                break
    2212            for p in ensure_list(prop):
    2213                properties.append(p)
    2214
    2215        if properties:
    2216            return self.expression(exp.Properties, expressions=properties)
    2217
    2218        return None
    2219
    2220    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
    2221        return self.expression(
    2222            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
    2223        )
    2224
    2225    def _parse_security(self) -> t.Optional[exp.SecurityProperty]:
    2226        if self._match_texts(("DEFINER", "INVOKER")):
    2227            security_specifier = self._prev.text.upper()
    2228            return self.expression(exp.SecurityProperty, this=security_specifier)
    2229        return None
    2230
    2231    def _parse_settings_property(self) -> exp.SettingsProperty:
    2232        return self.expression(
    2233            exp.SettingsProperty, expressions=self._parse_csv(self._parse_assignment)
    2234        )
    2235
    2236    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
    2237        if self._index >= 2:
    2238            pre_volatile_token = self._tokens[self._index - 2]
    2239        else:
    2240            pre_volatile_token = None
    2241
    2242        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
    2243            return exp.VolatileProperty()
    2244
    2245        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
    2246
    2247    def _parse_retention_period(self) -> exp.Var:
    2248        # Parse TSQL's HISTORY_RETENTION_PERIOD: {INFINITE | <number> DAY | DAYS | MONTH ...}
    2249        number = self._parse_number()
    2250        number_str = f"{number} " if number else ""
    2251        unit = self._parse_var(any_token=True)
    2252        return exp.var(f"{number_str}{unit}")
    2253
    2254    def _parse_system_versioning_property(
    2255        self, with_: bool = False
    2256    ) -> exp.WithSystemVersioningProperty:
    2257        self._match(TokenType.EQ)
    2258        prop = self.expression(
    2259            exp.WithSystemVersioningProperty,
    2260            **{  # type: ignore
    2261                "on": True,
    2262                "with": with_,
    2263            },
    2264        )
    2265
    2266        if self._match_text_seq("OFF"):
    2267            prop.set("on", False)
    2268            return prop
    2269
    2270        self._match(TokenType.ON)
    2271        if self._match(TokenType.L_PAREN):
    2272            while self._curr and not self._match(TokenType.R_PAREN):
    2273                if self._match_text_seq("HISTORY_TABLE", "="):
    2274                    prop.set("this", self._parse_table_parts())
    2275                elif self._match_text_seq("DATA_CONSISTENCY_CHECK", "="):
    2276                    prop.set("data_consistency", self._advance_any() and self._prev.text.upper())
    2277                elif self._match_text_seq("HISTORY_RETENTION_PERIOD", "="):
    2278                    prop.set("retention_period", self._parse_retention_period())
    2279
    2280                self._match(TokenType.COMMA)
    2281
    2282        return prop
    2283
    2284    def _parse_data_deletion_property(self) -> exp.DataDeletionProperty:
    2285        self._match(TokenType.EQ)
    2286        on = self._match_text_seq("ON") or not self._match_text_seq("OFF")
    2287        prop = self.expression(exp.DataDeletionProperty, on=on)
    2288
    2289        if self._match(TokenType.L_PAREN):
    2290            while self._curr and not self._match(TokenType.R_PAREN):
    2291                if self._match_text_seq("FILTER_COLUMN", "="):
    2292                    prop.set("filter_column", self._parse_column())
    2293                elif self._match_text_seq("RETENTION_PERIOD", "="):
    2294                    prop.set("retention_period", self._parse_retention_period())
    2295
    2296                self._match(TokenType.COMMA)
    2297
    2298        return prop
    2299
    2300    def _parse_distributed_property(self) -> exp.DistributedByProperty:
    2301        kind = "HASH"
    2302        expressions: t.Optional[t.List[exp.Expression]] = None
    2303        if self._match_text_seq("BY", "HASH"):
    2304            expressions = self._parse_wrapped_csv(self._parse_id_var)
    2305        elif self._match_text_seq("BY", "RANDOM"):
    2306            kind = "RANDOM"
    2307
    2308        # If the BUCKETS keyword is not present, the number of buckets is AUTO
    2309        buckets: t.Optional[exp.Expression] = None
    2310        if self._match_text_seq("BUCKETS") and not self._match_text_seq("AUTO"):
    2311            buckets = self._parse_number()
    2312
    2313        return self.expression(
    2314            exp.DistributedByProperty,
    2315            expressions=expressions,
    2316            kind=kind,
    2317            buckets=buckets,
    2318            order=self._parse_order(),
    2319        )
    2320
    2321    def _parse_composite_key_property(self, expr_type: t.Type[E]) -> E:
    2322        self._match_text_seq("KEY")
    2323        expressions = self._parse_wrapped_id_vars()
    2324        return self.expression(expr_type, expressions=expressions)
    2325
    2326    def _parse_with_property(self) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
    2327        if self._match_text_seq("(", "SYSTEM_VERSIONING"):
    2328            prop = self._parse_system_versioning_property(with_=True)
    2329            self._match_r_paren()
    2330            return prop
    2331
    2332        if self._match(TokenType.L_PAREN, advance=False):
    2333            return self._parse_wrapped_properties()
    2334
    2335        if self._match_text_seq("JOURNAL"):
    2336            return self._parse_withjournaltable()
    2337
    2338        if self._match_texts(self.VIEW_ATTRIBUTES):
    2339            return self.expression(exp.ViewAttributeProperty, this=self._prev.text.upper())
    2340
    2341        if self._match_text_seq("DATA"):
    2342            return self._parse_withdata(no=False)
    2343        elif self._match_text_seq("NO", "DATA"):
    2344            return self._parse_withdata(no=True)
    2345
    2346        if self._match(TokenType.SERDE_PROPERTIES, advance=False):
    2347            return self._parse_serde_properties(with_=True)
    2348
    2349        if self._match(TokenType.SCHEMA):
    2350            return self.expression(
    2351                exp.WithSchemaBindingProperty,
    2352                this=self._parse_var_from_options(self.SCHEMA_BINDING_OPTIONS),
    2353            )
    2354
    2355        if self._match_texts(self.PROCEDURE_OPTIONS, advance=False):
    2356            return self.expression(
    2357                exp.WithProcedureOptions, expressions=self._parse_csv(self._parse_procedure_option)
    2358            )
    2359
    2360        if not self._next:
    2361            return None
    2362
    2363        return self._parse_withisolatedloading()
    2364
    2365    def _parse_procedure_option(self) -> exp.Expression | None:
    2366        if self._match_text_seq("EXECUTE", "AS"):
    2367            return self.expression(
    2368                exp.ExecuteAsProperty,
    2369                this=self._parse_var_from_options(self.EXECUTE_AS_OPTIONS, raise_unmatched=False)
    2370                or self._parse_string(),
    2371            )
    2372
    2373        return self._parse_var_from_options(self.PROCEDURE_OPTIONS)
    2374
    2375    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
    2376    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
    2377        self._match(TokenType.EQ)
    2378
    2379        user = self._parse_id_var()
    2380        self._match(TokenType.PARAMETER)
    2381        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
    2382
    2383        if not user or not host:
    2384            return None
    2385
    2386        return exp.DefinerProperty(this=f"{user}@{host}")
    2387
    2388    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
    2389        self._match(TokenType.TABLE)
    2390        self._match(TokenType.EQ)
    2391        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
    2392
    2393    def _parse_log(self, no: bool = False) -> exp.LogProperty:
    2394        return self.expression(exp.LogProperty, no=no)
    2395
    2396    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
    2397        return self.expression(exp.JournalProperty, **kwargs)
    2398
    2399    def _parse_checksum(self) -> exp.ChecksumProperty:
    2400        self._match(TokenType.EQ)
    2401
    2402        on = None
    2403        if self._match(TokenType.ON):
    2404            on = True
    2405        elif self._match_text_seq("OFF"):
    2406            on = False
    2407
    2408        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
    2409
    2410    def _parse_cluster(self, wrapped: bool = False) -> exp.Cluster:
    2411        return self.expression(
    2412            exp.Cluster,
    2413            expressions=(
    2414                self._parse_wrapped_csv(self._parse_ordered)
    2415                if wrapped
    2416                else self._parse_csv(self._parse_ordered)
    2417            ),
    2418        )
    2419
    2420    def _parse_clustered_by(self) -> exp.ClusteredByProperty:
    2421        self._match_text_seq("BY")
    2422
    2423        self._match_l_paren()
    2424        expressions = self._parse_csv(self._parse_column)
    2425        self._match_r_paren()
    2426
    2427        if self._match_text_seq("SORTED", "BY"):
    2428            self._match_l_paren()
    2429            sorted_by = self._parse_csv(self._parse_ordered)
    2430            self._match_r_paren()
    2431        else:
    2432            sorted_by = None
    2433
    2434        self._match(TokenType.INTO)
    2435        buckets = self._parse_number()
    2436        self._match_text_seq("BUCKETS")
    2437
    2438        return self.expression(
    2439            exp.ClusteredByProperty,
    2440            expressions=expressions,
    2441            sorted_by=sorted_by,
    2442            buckets=buckets,
    2443        )
    2444
    2445    def _parse_copy_property(self) -> t.Optional[exp.CopyGrantsProperty]:
    2446        if not self._match_text_seq("GRANTS"):
    2447            self._retreat(self._index - 1)
    2448            return None
    2449
    2450        return self.expression(exp.CopyGrantsProperty)
    2451
    2452    def _parse_freespace(self) -> exp.FreespaceProperty:
    2453        self._match(TokenType.EQ)
    2454        return self.expression(
    2455            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
    2456        )
    2457
    2458    def _parse_mergeblockratio(
    2459        self, no: bool = False, default: bool = False
    2460    ) -> exp.MergeBlockRatioProperty:
    2461        if self._match(TokenType.EQ):
    2462            return self.expression(
    2463                exp.MergeBlockRatioProperty,
    2464                this=self._parse_number(),
    2465                percent=self._match(TokenType.PERCENT),
    2466            )
    2467
    2468        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
    2469
    2470    def _parse_datablocksize(
    2471        self,
    2472        default: t.Optional[bool] = None,
    2473        minimum: t.Optional[bool] = None,
    2474        maximum: t.Optional[bool] = None,
    2475    ) -> exp.DataBlocksizeProperty:
    2476        self._match(TokenType.EQ)
    2477        size = self._parse_number()
    2478
    2479        units = None
    2480        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
    2481            units = self._prev.text
    2482
    2483        return self.expression(
    2484            exp.DataBlocksizeProperty,
    2485            size=size,
    2486            units=units,
    2487            default=default,
    2488            minimum=minimum,
    2489            maximum=maximum,
    2490        )
    2491
    2492    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
    2493        self._match(TokenType.EQ)
    2494        always = self._match_text_seq("ALWAYS")
    2495        manual = self._match_text_seq("MANUAL")
    2496        never = self._match_text_seq("NEVER")
    2497        default = self._match_text_seq("DEFAULT")
    2498
    2499        autotemp = None
    2500        if self._match_text_seq("AUTOTEMP"):
    2501            autotemp = self._parse_schema()
    2502
    2503        return self.expression(
    2504            exp.BlockCompressionProperty,
    2505            always=always,
    2506            manual=manual,
    2507            never=never,
    2508            default=default,
    2509            autotemp=autotemp,
    2510        )
    2511
    2512    def _parse_withisolatedloading(self) -> t.Optional[exp.IsolatedLoadingProperty]:
    2513        index = self._index
    2514        no = self._match_text_seq("NO")
    2515        concurrent = self._match_text_seq("CONCURRENT")
    2516
    2517        if not self._match_text_seq("ISOLATED", "LOADING"):
    2518            self._retreat(index)
    2519            return None
    2520
    2521        target = self._parse_var_from_options(self.ISOLATED_LOADING_OPTIONS, raise_unmatched=False)
    2522        return self.expression(
    2523            exp.IsolatedLoadingProperty, no=no, concurrent=concurrent, target=target
    2524        )
    2525
    2526    def _parse_locking(self) -> exp.LockingProperty:
    2527        if self._match(TokenType.TABLE):
    2528            kind = "TABLE"
    2529        elif self._match(TokenType.VIEW):
    2530            kind = "VIEW"
    2531        elif self._match(TokenType.ROW):
    2532            kind = "ROW"
    2533        elif self._match_text_seq("DATABASE"):
    2534            kind = "DATABASE"
    2535        else:
    2536            kind = None
    2537
    2538        if kind in ("DATABASE", "TABLE", "VIEW"):
    2539            this = self._parse_table_parts()
    2540        else:
    2541            this = None
    2542
    2543        if self._match(TokenType.FOR):
    2544            for_or_in = "FOR"
    2545        elif self._match(TokenType.IN):
    2546            for_or_in = "IN"
    2547        else:
    2548            for_or_in = None
    2549
    2550        if self._match_text_seq("ACCESS"):
    2551            lock_type = "ACCESS"
    2552        elif self._match_texts(("EXCL", "EXCLUSIVE")):
    2553            lock_type = "EXCLUSIVE"
    2554        elif self._match_text_seq("SHARE"):
    2555            lock_type = "SHARE"
    2556        elif self._match_text_seq("READ"):
    2557            lock_type = "READ"
    2558        elif self._match_text_seq("WRITE"):
    2559            lock_type = "WRITE"
    2560        elif self._match_text_seq("CHECKSUM"):
    2561            lock_type = "CHECKSUM"
    2562        else:
    2563            lock_type = None
    2564
    2565        override = self._match_text_seq("OVERRIDE")
    2566
    2567        return self.expression(
    2568            exp.LockingProperty,
    2569            this=this,
    2570            kind=kind,
    2571            for_or_in=for_or_in,
    2572            lock_type=lock_type,
    2573            override=override,
    2574        )
    2575
    2576    def _parse_partition_by(self) -> t.List[exp.Expression]:
    2577        if self._match(TokenType.PARTITION_BY):
    2578            return self._parse_csv(self._parse_assignment)
    2579        return []
    2580
    2581    def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
    2582        def _parse_partition_bound_expr() -> t.Optional[exp.Expression]:
    2583            if self._match_text_seq("MINVALUE"):
    2584                return exp.var("MINVALUE")
    2585            if self._match_text_seq("MAXVALUE"):
    2586                return exp.var("MAXVALUE")
    2587            return self._parse_bitwise()
    2588
    2589        this: t.Optional[exp.Expression | t.List[exp.Expression]] = None
    2590        expression = None
    2591        from_expressions = None
    2592        to_expressions = None
    2593
    2594        if self._match(TokenType.IN):
    2595            this = self._parse_wrapped_csv(self._parse_bitwise)
    2596        elif self._match(TokenType.FROM):
    2597            from_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
    2598            self._match_text_seq("TO")
    2599            to_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
    2600        elif self._match_text_seq("WITH", "(", "MODULUS"):
    2601            this = self._parse_number()
    2602            self._match_text_seq(",", "REMAINDER")
    2603            expression = self._parse_number()
    2604            self._match_r_paren()
    2605        else:
    2606            self.raise_error("Failed to parse partition bound spec.")
    2607
    2608        return self.expression(
    2609            exp.PartitionBoundSpec,
    2610            this=this,
    2611            expression=expression,
    2612            from_expressions=from_expressions,
    2613            to_expressions=to_expressions,
    2614        )
    2615
    2616    # https://www.postgresql.org/docs/current/sql-createtable.html
    2617    def _parse_partitioned_of(self) -> t.Optional[exp.PartitionedOfProperty]:
    2618        if not self._match_text_seq("OF"):
    2619            self._retreat(self._index - 1)
    2620            return None
    2621
    2622        this = self._parse_table(schema=True)
    2623
    2624        if self._match(TokenType.DEFAULT):
    2625            expression: exp.Var | exp.PartitionBoundSpec = exp.var("DEFAULT")
    2626        elif self._match_text_seq("FOR", "VALUES"):
    2627            expression = self._parse_partition_bound_spec()
    2628        else:
    2629            self.raise_error("Expecting either DEFAULT or FOR VALUES clause.")
    2630
    2631        return self.expression(exp.PartitionedOfProperty, this=this, expression=expression)
    2632
    2633    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
    2634        self._match(TokenType.EQ)
    2635        return self.expression(
    2636            exp.PartitionedByProperty,
    2637            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
    2638        )
    2639
    2640    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
    2641        if self._match_text_seq("AND", "STATISTICS"):
    2642            statistics = True
    2643        elif self._match_text_seq("AND", "NO", "STATISTICS"):
    2644            statistics = False
    2645        else:
    2646            statistics = None
    2647
    2648        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
    2649
    2650    def _parse_contains_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
    2651        if self._match_text_seq("SQL"):
    2652            return self.expression(exp.SqlReadWriteProperty, this="CONTAINS SQL")
    2653        return None
    2654
    2655    def _parse_modifies_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
    2656        if self._match_text_seq("SQL", "DATA"):
    2657            return self.expression(exp.SqlReadWriteProperty, this="MODIFIES SQL DATA")
    2658        return None
    2659
    2660    def _parse_no_property(self) -> t.Optional[exp.Expression]:
    2661        if self._match_text_seq("PRIMARY", "INDEX"):
    2662            return exp.NoPrimaryIndexProperty()
    2663        if self._match_text_seq("SQL"):
    2664            return self.expression(exp.SqlReadWriteProperty, this="NO SQL")
    2665        return None
    2666
    2667    def _parse_on_property(self) -> t.Optional[exp.Expression]:
    2668        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
    2669            return exp.OnCommitProperty()
    2670        if self._match_text_seq("COMMIT", "DELETE", "ROWS"):
    2671            return exp.OnCommitProperty(delete=True)
    2672        return self.expression(exp.OnProperty, this=self._parse_schema(self._parse_id_var()))
    2673
    2674    def _parse_reads_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
    2675        if self._match_text_seq("SQL", "DATA"):
    2676            return self.expression(exp.SqlReadWriteProperty, this="READS SQL DATA")
    2677        return None
    2678
    2679    def _parse_distkey(self) -> exp.DistKeyProperty:
    2680        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
    2681
    2682    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
    2683        table = self._parse_table(schema=True)
    2684
    2685        options = []
    2686        while self._match_texts(("INCLUDING", "EXCLUDING")):
    2687            this = self._prev.text.upper()
    2688
    2689            id_var = self._parse_id_var()
    2690            if not id_var:
    2691                return None
    2692
    2693            options.append(
    2694                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
    2695            )
    2696
    2697        return self.expression(exp.LikeProperty, this=table, expressions=options)
    2698
    2699    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
    2700        return self.expression(
    2701            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
    2702        )
    2703
    2704    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
    2705        self._match(TokenType.EQ)
    2706        return self.expression(
    2707            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
    2708        )
    2709
    2710    def _parse_remote_with_connection(self) -> exp.RemoteWithConnectionModelProperty:
    2711        self._match_text_seq("WITH", "CONNECTION")
    2712        return self.expression(
    2713            exp.RemoteWithConnectionModelProperty, this=self._parse_table_parts()
    2714        )
    2715
    2716    def _parse_returns(self) -> exp.ReturnsProperty:
    2717        value: t.Optional[exp.Expression]
    2718        null = None
    2719        is_table = self._match(TokenType.TABLE)
    2720
    2721        if is_table:
    2722            if self._match(TokenType.LT):
    2723                value = self.expression(
    2724                    exp.Schema,
    2725                    this="TABLE",
    2726                    expressions=self._parse_csv(self._parse_struct_types),
    2727                )
    2728                if not self._match(TokenType.GT):
    2729                    self.raise_error("Expecting >")
    2730            else:
    2731                value = self._parse_schema(exp.var("TABLE"))
    2732        elif self._match_text_seq("NULL", "ON", "NULL", "INPUT"):
    2733            null = True
    2734            value = None
    2735        else:
    2736            value = self._parse_types()
    2737
    2738        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table, null=null)
    2739
    2740    def _parse_describe(self) -> exp.Describe:
    2741        kind = self._match_set(self.CREATABLES) and self._prev.text
    2742        style = self._match_texts(self.DESCRIBE_STYLES) and self._prev.text.upper()
    2743        if self._match(TokenType.DOT):
    2744            style = None
    2745            self._retreat(self._index - 2)
    2746
    2747        format = self._parse_property() if self._match(TokenType.FORMAT, advance=False) else None
    2748
    2749        if self._match_set(self.STATEMENT_PARSERS, advance=False):
    2750            this = self._parse_statement()
    2751        else:
    2752            this = self._parse_table(schema=True)
    2753
    2754        properties = self._parse_properties()
    2755        expressions = properties.expressions if properties else None
    2756        partition = self._parse_partition()
    2757        return self.expression(
    2758            exp.Describe,
    2759            this=this,
    2760            style=style,
    2761            kind=kind,
    2762            expressions=expressions,
    2763            partition=partition,
    2764            format=format,
    2765        )
    2766
    2767    def _parse_multitable_inserts(self, comments: t.Optional[t.List[str]]) -> exp.MultitableInserts:
    2768        kind = self._prev.text.upper()
    2769        expressions = []
    2770
    2771        def parse_conditional_insert() -> t.Optional[exp.ConditionalInsert]:
    2772            if self._match(TokenType.WHEN):
    2773                expression = self._parse_disjunction()
    2774                self._match(TokenType.THEN)
    2775            else:
    2776                expression = None
    2777
    2778            else_ = self._match(TokenType.ELSE)
    2779
    2780            if not self._match(TokenType.INTO):
    2781                return None
    2782
    2783            return self.expression(
    2784                exp.ConditionalInsert,
    2785                this=self.expression(
    2786                    exp.Insert,
    2787                    this=self._parse_table(schema=True),
    2788                    expression=self._parse_derived_table_values(),
    2789                ),
    2790                expression=expression,
    2791                else_=else_,
    2792            )
    2793
    2794        expression = parse_conditional_insert()
    2795        while expression is not None:
    2796            expressions.append(expression)
    2797            expression = parse_conditional_insert()
    2798
    2799        return self.expression(
    2800            exp.MultitableInserts,
    2801            kind=kind,
    2802            comments=comments,
    2803            expressions=expressions,
    2804            source=self._parse_table(),
    2805        )
    2806
    2807    def _parse_insert(self) -> t.Union[exp.Insert, exp.MultitableInserts]:
    2808        comments = []
    2809        hint = self._parse_hint()
    2810        overwrite = self._match(TokenType.OVERWRITE)
    2811        ignore = self._match(TokenType.IGNORE)
    2812        local = self._match_text_seq("LOCAL")
    2813        alternative = None
    2814        is_function = None
    2815
    2816        if self._match_text_seq("DIRECTORY"):
    2817            this: t.Optional[exp.Expression] = self.expression(
    2818                exp.Directory,
    2819                this=self._parse_var_or_string(),
    2820                local=local,
    2821                row_format=self._parse_row_format(match_row=True),
    2822            )
    2823        else:
    2824            if self._match_set((TokenType.FIRST, TokenType.ALL)):
    2825                comments += ensure_list(self._prev_comments)
    2826                return self._parse_multitable_inserts(comments)
    2827
    2828            if self._match(TokenType.OR):
    2829                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
    2830
    2831            self._match(TokenType.INTO)
    2832            comments += ensure_list(self._prev_comments)
    2833            self._match(TokenType.TABLE)
    2834            is_function = self._match(TokenType.FUNCTION)
    2835
    2836            this = (
    2837                self._parse_table(schema=True, parse_partition=True)
    2838                if not is_function
    2839                else self._parse_function()
    2840            )
    2841            if isinstance(this, exp.Table) and self._match(TokenType.ALIAS, advance=False):
    2842                this.set("alias", self._parse_table_alias())
    2843
    2844        returning = self._parse_returning()
    2845
    2846        return self.expression(
    2847            exp.Insert,
    2848            comments=comments,
    2849            hint=hint,
    2850            is_function=is_function,
    2851            this=this,
    2852            stored=self._match_text_seq("STORED") and self._parse_stored(),
    2853            by_name=self._match_text_seq("BY", "NAME"),
    2854            exists=self._parse_exists(),
    2855            where=self._match_pair(TokenType.REPLACE, TokenType.WHERE) and self._parse_assignment(),
    2856            partition=self._match(TokenType.PARTITION_BY) and self._parse_partitioned_by(),
    2857            settings=self._match_text_seq("SETTINGS") and self._parse_settings_property(),
    2858            expression=self._parse_derived_table_values() or self._parse_ddl_select(),
    2859            conflict=self._parse_on_conflict(),
    2860            returning=returning or self._parse_returning(),
    2861            overwrite=overwrite,
    2862            alternative=alternative,
    2863            ignore=ignore,
    2864            source=self._match(TokenType.TABLE) and self._parse_table(),
    2865        )
    2866
    2867    def _parse_kill(self) -> exp.Kill:
    2868        kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
    2869
    2870        return self.expression(
    2871            exp.Kill,
    2872            this=self._parse_primary(),
    2873            kind=kind,
    2874        )
    2875
    2876    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
    2877        conflict = self._match_text_seq("ON", "CONFLICT")
    2878        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
    2879
    2880        if not conflict and not duplicate:
    2881            return None
    2882
    2883        conflict_keys = None
    2884        constraint = None
    2885
    2886        if conflict:
    2887            if self._match_text_seq("ON", "CONSTRAINT"):
    2888                constraint = self._parse_id_var()
    2889            elif self._match(TokenType.L_PAREN):
    2890                conflict_keys = self._parse_csv(self._parse_id_var)
    2891                self._match_r_paren()
    2892
    2893        action = self._parse_var_from_options(self.CONFLICT_ACTIONS)
    2894        if self._prev.token_type == TokenType.UPDATE:
    2895            self._match(TokenType.SET)
    2896            expressions = self._parse_csv(self._parse_equality)
    2897        else:
    2898            expressions = None
    2899
    2900        return self.expression(
    2901            exp.OnConflict,
    2902            duplicate=duplicate,
    2903            expressions=expressions,
    2904            action=action,
    2905            conflict_keys=conflict_keys,
    2906            constraint=constraint,
    2907            where=self._parse_where(),
    2908        )
    2909
    2910    def _parse_returning(self) -> t.Optional[exp.Returning]:
    2911        if not self._match(TokenType.RETURNING):
    2912            return None
    2913        return self.expression(
    2914            exp.Returning,
    2915            expressions=self._parse_csv(self._parse_expression),
    2916            into=self._match(TokenType.INTO) and self._parse_table_part(),
    2917        )
    2918
    2919    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
    2920        if not self._match(TokenType.FORMAT):
    2921            return None
    2922        return self._parse_row_format()
    2923
    2924    def _parse_serde_properties(self, with_: bool = False) -> t.Optional[exp.SerdeProperties]:
    2925        index = self._index
    2926        with_ = with_ or self._match_text_seq("WITH")
    2927
    2928        if not self._match(TokenType.SERDE_PROPERTIES):
    2929            self._retreat(index)
    2930            return None
    2931        return self.expression(
    2932            exp.SerdeProperties,
    2933            **{  # type: ignore
    2934                "expressions": self._parse_wrapped_properties(),
    2935                "with": with_,
    2936            },
    2937        )
    2938
    2939    def _parse_row_format(
    2940        self, match_row: bool = False
    2941    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
    2942        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
    2943            return None
    2944
    2945        if self._match_text_seq("SERDE"):
    2946            this = self._parse_string()
    2947
    2948            serde_properties = self._parse_serde_properties()
    2949
    2950            return self.expression(
    2951                exp.RowFormatSerdeProperty, this=this, serde_properties=serde_properties
    2952            )
    2953
    2954        self._match_text_seq("DELIMITED")
    2955
    2956        kwargs = {}
    2957
    2958        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
    2959            kwargs["fields"] = self._parse_string()
    2960            if self._match_text_seq("ESCAPED", "BY"):
    2961                kwargs["escaped"] = self._parse_string()
    2962        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
    2963            kwargs["collection_items"] = self._parse_string()
    2964        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
    2965            kwargs["map_keys"] = self._parse_string()
    2966        if self._match_text_seq("LINES", "TERMINATED", "BY"):
    2967            kwargs["lines"] = self._parse_string()
    2968        if self._match_text_seq("NULL", "DEFINED", "AS"):
    2969            kwargs["null"] = self._parse_string()
    2970
    2971        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
    2972
    2973    def _parse_load(self) -> exp.LoadData | exp.Command:
    2974        if self._match_text_seq("DATA"):
    2975            local = self._match_text_seq("LOCAL")
    2976            self._match_text_seq("INPATH")
    2977            inpath = self._parse_string()
    2978            overwrite = self._match(TokenType.OVERWRITE)
    2979            self._match_pair(TokenType.INTO, TokenType.TABLE)
    2980
    2981            return self.expression(
    2982                exp.LoadData,
    2983                this=self._parse_table(schema=True),
    2984                local=local,
    2985                overwrite=overwrite,
    2986                inpath=inpath,
    2987                partition=self._parse_partition(),
    2988                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
    2989                serde=self._match_text_seq("SERDE") and self._parse_string(),
    2990            )
    2991        return self._parse_as_command(self._prev)
    2992
    2993    def _parse_delete(self) -> exp.Delete:
    2994        # This handles MySQL's "Multiple-Table Syntax"
    2995        # https://dev.mysql.com/doc/refman/8.0/en/delete.html
    2996        tables = None
    2997        if not self._match(TokenType.FROM, advance=False):
    2998            tables = self._parse_csv(self._parse_table) or None
    2999
    3000        returning = self._parse_returning()
    3001
    3002        return self.expression(
    3003            exp.Delete,
    3004            tables=tables,
    3005            this=self._match(TokenType.FROM) and self._parse_table(joins=True),
    3006            using=self._match(TokenType.USING) and self._parse_table(joins=True),
    3007            cluster=self._match(TokenType.ON) and self._parse_on_property(),
    3008            where=self._parse_where(),
    3009            returning=returning or self._parse_returning(),
    3010            limit=self._parse_limit(),
    3011        )
    3012
    3013    def _parse_update(self) -> exp.Update:
    3014        this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
    3015        expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
    3016        returning = self._parse_returning()
    3017        return self.expression(
    3018            exp.Update,
    3019            **{  # type: ignore
    3020                "this": this,
    3021                "expressions": expressions,
    3022                "from": self._parse_from(joins=True),
    3023                "where": self._parse_where(),
    3024                "returning": returning or self._parse_returning(),
    3025                "order": self._parse_order(),
    3026                "limit": self._parse_limit(),
    3027            },
    3028        )
    3029
    3030    def _parse_use(self) -> exp.Use:
    3031        return self.expression(
    3032            exp.Use,
    3033            kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
    3034            this=self._parse_table(schema=False),
    3035        )
    3036
    3037    def _parse_uncache(self) -> exp.Uncache:
    3038        if not self._match(TokenType.TABLE):
    3039            self.raise_error("Expecting TABLE after UNCACHE")
    3040
    3041        return self.expression(
    3042            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
    3043        )
    3044
    3045    def _parse_cache(self) -> exp.Cache:
    3046        lazy = self._match_text_seq("LAZY")
    3047        self._match(TokenType.TABLE)
    3048        table = self._parse_table(schema=True)
    3049
    3050        options = []
    3051        if self._match_text_seq("OPTIONS"):
    3052            self._match_l_paren()
    3053            k = self._parse_string()
    3054            self._match(TokenType.EQ)
    3055            v = self._parse_string()
    3056            options = [k, v]
    3057            self._match_r_paren()
    3058
    3059        self._match(TokenType.ALIAS)
    3060        return self.expression(
    3061            exp.Cache,
    3062            this=table,
    3063            lazy=lazy,
    3064            options=options,
    3065            expression=self._parse_select(nested=True),
    3066        )
    3067
    3068    def _parse_partition(self) -> t.Optional[exp.Partition]:
    3069        if not self._match_texts(self.PARTITION_KEYWORDS):
    3070            return None
    3071
    3072        return self.expression(
    3073            exp.Partition,
    3074            subpartition=self._prev.text.upper() == "SUBPARTITION",
    3075            expressions=self._parse_wrapped_csv(self._parse_assignment),
    3076        )
    3077
    3078    def _parse_value(self, values: bool = True) -> t.Optional[exp.Tuple]:
    3079        def _parse_value_expression() -> t.Optional[exp.Expression]:
    3080            if self.dialect.SUPPORTS_VALUES_DEFAULT and self._match(TokenType.DEFAULT):
    3081                return exp.var(self._prev.text.upper())
    3082            return self._parse_expression()
    3083
    3084        if self._match(TokenType.L_PAREN):
    3085            expressions = self._parse_csv(_parse_value_expression)
    3086            self._match_r_paren()
    3087            return self.expression(exp.Tuple, expressions=expressions)
    3088
    3089        # In some dialects we can have VALUES 1, 2 which results in 1 column & 2 rows.
    3090        expression = self._parse_expression()
    3091        if expression:
    3092            return self.expression(exp.Tuple, expressions=[expression])
    3093        return None
    3094
    3095    def _parse_projections(self) -> t.List[exp.Expression]:
    3096        return self._parse_expressions()
    3097
    3098    def _parse_wrapped_select(self, table: bool = False) -> t.Optional[exp.Expression]:
    3099        if self._match_set((TokenType.PIVOT, TokenType.UNPIVOT)):
    3100            this: t.Optional[exp.Expression] = self._parse_simplified_pivot(
    3101                is_unpivot=self._prev.token_type == TokenType.UNPIVOT
    3102            )
    3103        elif self._match(TokenType.FROM):
    3104            from_ = self._parse_from(skip_from_token=True)
    3105            # Support parentheses for duckdb FROM-first syntax
    3106            select = self._parse_select()
    3107            if select:
    3108                select.set("from", from_)
    3109                this = select
    3110            else:
    3111                this = exp.select("*").from_(t.cast(exp.From, from_))
    3112        else:
    3113            this = (
    3114                self._parse_table()
    3115                if table
    3116                else self._parse_select(nested=True, parse_set_operation=False)
    3117            )
    3118
    3119            # Transform exp.Values into a exp.Table to pass through parse_query_modifiers
    3120            # in case a modifier (e.g. join) is following
    3121            if table and isinstance(this, exp.Values) and this.alias:
    3122                alias = this.args["alias"].pop()
    3123                this = exp.Table(this=this, alias=alias)
    3124
    3125            this = self._parse_query_modifiers(self._parse_set_operations(this))
    3126
    3127        return this
    3128
    3129    def _parse_select(
    3130        self,
    3131        nested: bool = False,
    3132        table: bool = False,
    3133        parse_subquery_alias: bool = True,
    3134        parse_set_operation: bool = True,
    3135    ) -> t.Optional[exp.Expression]:
    3136        cte = self._parse_with()
    3137
    3138        if cte:
    3139            this = self._parse_statement()
    3140
    3141            if not this:
    3142                self.raise_error("Failed to parse any statement following CTE")
    3143                return cte
    3144
    3145            if "with" in this.arg_types:
    3146                this.set("with", cte)
    3147            else:
    3148                self.raise_error(f"{this.key} does not support CTE")
    3149                this = cte
    3150
    3151            return this
    3152
    3153        # duckdb supports leading with FROM x
    3154        from_ = self._parse_from() if self._match(TokenType.FROM, advance=False) else None
    3155
    3156        if self._match(TokenType.SELECT):
    3157            comments = self._prev_comments
    3158
    3159            hint = self._parse_hint()
    3160
    3161            if self._next and not self._next.token_type == TokenType.DOT:
    3162                all_ = self._match(TokenType.ALL)
    3163                distinct = self._match_set(self.DISTINCT_TOKENS)
    3164            else:
    3165                all_, distinct = None, None
    3166
    3167            kind = (
    3168                self._match(TokenType.ALIAS)
    3169                and self._match_texts(("STRUCT", "VALUE"))
    3170                and self._prev.text.upper()
    3171            )
    3172
    3173            if distinct:
    3174                distinct = self.expression(
    3175                    exp.Distinct,
    3176                    on=self._parse_value(values=False) if self._match(TokenType.ON) else None,
    3177                )
    3178
    3179            if all_ and distinct:
    3180                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
    3181
    3182            operation_modifiers = []
    3183            while self._curr and self._match_texts(self.OPERATION_MODIFIERS):
    3184                operation_modifiers.append(exp.var(self._prev.text.upper()))
    3185
    3186            limit = self._parse_limit(top=True)
    3187            projections = self._parse_projections()
    3188
    3189            this = self.expression(
    3190                exp.Select,
    3191                kind=kind,
    3192                hint=hint,
    3193                distinct=distinct,
    3194                expressions=projections,
    3195                limit=limit,
    3196                operation_modifiers=operation_modifiers or None,
    3197            )
    3198            this.comments = comments
    3199
    3200            into = self._parse_into()
    3201            if into:
    3202                this.set("into", into)
    3203
    3204            if not from_:
    3205                from_ = self._parse_from()
    3206
    3207            if from_:
    3208                this.set("from", from_)
    3209
    3210            this = self._parse_query_modifiers(this)
    3211        elif (table or nested) and self._match(TokenType.L_PAREN):
    3212            this = self._parse_wrapped_select(table=table)
    3213
    3214            # We return early here so that the UNION isn't attached to the subquery by the
    3215            # following call to _parse_set_operations, but instead becomes the parent node
    3216            self._match_r_paren()
    3217            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
    3218        elif self._match(TokenType.VALUES, advance=False):
    3219            this = self._parse_derived_table_values()
    3220        elif from_:
    3221            this = exp.select("*").from_(from_.this, copy=False)
    3222        elif self._match(TokenType.SUMMARIZE):
    3223            table = self._match(TokenType.TABLE)
    3224            this = self._parse_select() or self._parse_string() or self._parse_table()
    3225            return self.expression(exp.Summarize, this=this, table=table)
    3226        elif self._match(TokenType.DESCRIBE):
    3227            this = self._parse_describe()
    3228        elif self._match_text_seq("STREAM"):
    3229            this = self._parse_function()
    3230            if this:
    3231                this = self.expression(exp.Stream, this=this)
    3232            else:
    3233                self._retreat(self._index - 1)
    3234        else:
    3235            this = None
    3236
    3237        return self._parse_set_operations(this) if parse_set_operation else this
    3238
    3239    def _parse_recursive_with_search(self) -> t.Optional[exp.RecursiveWithSearch]:
    3240        self._match_text_seq("SEARCH")
    3241
    3242        kind = self._match_texts(self.RECURSIVE_CTE_SEARCH_KIND) and self._prev.text.upper()
    3243
    3244        if not kind:
    3245            return None
    3246
    3247        self._match_text_seq("FIRST", "BY")
    3248
    3249        return self.expression(
    3250            exp.RecursiveWithSearch,
    3251            kind=kind,
    3252            this=self._parse_id_var(),
    3253            expression=self._match_text_seq("SET") and self._parse_id_var(),
    3254            using=self._match_text_seq("USING") and self._parse_id_var(),
    3255        )
    3256
    3257    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
    3258        if not skip_with_token and not self._match(TokenType.WITH):
    3259            return None
    3260
    3261        comments = self._prev_comments
    3262        recursive = self._match(TokenType.RECURSIVE)
    3263
    3264        last_comments = None
    3265        expressions = []
    3266        while True:
    3267            cte = self._parse_cte()
    3268            if isinstance(cte, exp.CTE):
    3269                expressions.append(cte)
    3270                if last_comments:
    3271                    cte.add_comments(last_comments)
    3272
    3273            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
    3274                break
    3275            else:
    3276                self._match(TokenType.WITH)
    3277
    3278            last_comments = self._prev_comments
    3279
    3280        return self.expression(
    3281            exp.With,
    3282            comments=comments,
    3283            expressions=expressions,
    3284            recursive=recursive,
    3285            search=self._parse_recursive_with_search(),
    3286        )
    3287
    3288    def _parse_cte(self) -> t.Optional[exp.CTE]:
    3289        index = self._index
    3290
    3291        alias = self._parse_table_alias(self.ID_VAR_TOKENS)
    3292        if not alias or not alias.this:
    3293            self.raise_error("Expected CTE to have alias")
    3294
    3295        if not self._match(TokenType.ALIAS) and not self.OPTIONAL_ALIAS_TOKEN_CTE:
    3296            self._retreat(index)
    3297            return None
    3298
    3299        comments = self._prev_comments
    3300
    3301        if self._match_text_seq("NOT", "MATERIALIZED"):
    3302            materialized = False
    3303        elif self._match_text_seq("MATERIALIZED"):
    3304            materialized = True
    3305        else:
    3306            materialized = None
    3307
    3308        cte = self.expression(
    3309            exp.CTE,
    3310            this=self._parse_wrapped(self._parse_statement),
    3311            alias=alias,
    3312            materialized=materialized,
    3313            comments=comments,
    3314        )
    3315
    3316        if isinstance(cte.this, exp.Values):
    3317            cte.set("this", exp.select("*").from_(exp.alias_(cte.this, "_values", table=True)))
    3318
    3319        return cte
    3320
    3321    def _parse_table_alias(
    3322        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
    3323    ) -> t.Optional[exp.TableAlias]:
    3324        # In some dialects, LIMIT and OFFSET can act as both identifiers and keywords (clauses)
    3325        # so this section tries to parse the clause version and if it fails, it treats the token
    3326        # as an identifier (alias)
    3327        if self._can_parse_limit_or_offset():
    3328            return None
    3329
    3330        any_token = self._match(TokenType.ALIAS)
    3331        alias = (
    3332            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
    3333            or self._parse_string_as_identifier()
    3334        )
    3335
    3336        index = self._index
    3337        if self._match(TokenType.L_PAREN):
    3338            columns = self._parse_csv(self._parse_function_parameter)
    3339            self._match_r_paren() if columns else self._retreat(index)
    3340        else:
    3341            columns = None
    3342
    3343        if not alias and not columns:
    3344            return None
    3345
    3346        table_alias = self.expression(exp.TableAlias, this=alias, columns=columns)
    3347
    3348        # We bubble up comments from the Identifier to the TableAlias
    3349        if isinstance(alias, exp.Identifier):
    3350            table_alias.add_comments(alias.pop_comments())
    3351
    3352        return table_alias
    3353
    3354    def _parse_subquery(
    3355        self, this: t.Optional[exp.Expression], parse_alias: bool = True
    3356    ) -> t.Optional[exp.Subquery]:
    3357        if not this:
    3358            return None
    3359
    3360        return self.expression(
    3361            exp.Subquery,
    3362            this=this,
    3363            pivots=self._parse_pivots(),
    3364            alias=self._parse_table_alias() if parse_alias else None,
    3365            sample=self._parse_table_sample(),
    3366        )
    3367
    3368    def _implicit_unnests_to_explicit(self, this: E) -> E:
    3369        from sqlglot.optimizer.normalize_identifiers import normalize_identifiers as _norm
    3370
    3371        refs = {_norm(this.args["from"].this.copy(), dialect=self.dialect).alias_or_name}
    3372        for i, join in enumerate(this.args.get("joins") or []):
    3373            table = join.this
    3374            normalized_table = table.copy()
    3375            normalized_table.meta["maybe_column"] = True
    3376            normalized_table = _norm(normalized_table, dialect=self.dialect)
    3377
    3378            if isinstance(table, exp.Table) and not join.args.get("on"):
    3379                if normalized_table.parts[0].name in refs:
    3380                    table_as_column = table.to_column()
    3381                    unnest = exp.Unnest(expressions=[table_as_column])
    3382
    3383                    # Table.to_column creates a parent Alias node that we want to convert to
    3384                    # a TableAlias and attach to the Unnest, so it matches the parser's output
    3385                    if isinstance(table.args.get("alias"), exp.TableAlias):
    3386                        table_as_column.replace(table_as_column.this)
    3387                        exp.alias_(unnest, None, table=[table.args["alias"].this], copy=False)
    3388
    3389                    table.replace(unnest)
    3390
    3391            refs.add(normalized_table.alias_or_name)
    3392
    3393        return this
    3394
    3395    def _parse_query_modifiers(
    3396        self, this: t.Optional[exp.Expression]
    3397    ) -> t.Optional[exp.Expression]:
    3398        if isinstance(this, self.MODIFIABLES):
    3399            for join in self._parse_joins():
    3400                this.append("joins", join)
    3401            for lateral in iter(self._parse_lateral, None):
    3402                this.append("laterals", lateral)
    3403
    3404            while True:
    3405                if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
    3406                    parser = self.QUERY_MODIFIER_PARSERS[self._curr.token_type]
    3407                    key, expression = parser(self)
    3408
    3409                    if expression:
    3410                        this.set(key, expression)
    3411                        if key == "limit":
    3412                            offset = expression.args.pop("offset", None)
    3413
    3414                            if offset:
    3415                                offset = exp.Offset(expression=offset)
    3416                                this.set("offset", offset)
    3417
    3418                                limit_by_expressions = expression.expressions
    3419                                expression.set("expressions", None)
    3420                                offset.set("expressions", limit_by_expressions)
    3421                        continue
    3422                break
    3423
    3424        if self.SUPPORTS_IMPLICIT_UNNEST and this and this.args.get("from"):
    3425            this = self._implicit_unnests_to_explicit(this)
    3426
    3427        return this
    3428
    3429    def _parse_hint_fallback_to_string(self) -> t.Optional[exp.Hint]:
    3430        start = self._curr
    3431        while self._curr:
    3432            self._advance()
    3433
    3434        end = self._tokens[self._index - 1]
    3435        return exp.Hint(expressions=[self._find_sql(start, end)])
    3436
    3437    def _parse_hint_function_call(self) -> t.Optional[exp.Expression]:
    3438        return self._parse_function_call()
    3439
    3440    def _parse_hint_body(self) -> t.Optional[exp.Hint]:
    3441        start_index = self._index
    3442        should_fallback_to_string = False
    3443
    3444        hints = []
    3445        try:
    3446            for hint in iter(
    3447                lambda: self._parse_csv(
    3448                    lambda: self._parse_hint_function_call() or self._parse_var(upper=True),
    3449                ),
    3450                [],
    3451            ):
    3452                hints.extend(hint)
    3453        except ParseError:
    3454            should_fallback_to_string = True
    3455
    3456        if should_fallback_to_string or self._curr:
    3457            self._retreat(start_index)
    3458            return self._parse_hint_fallback_to_string()
    3459
    3460        return self.expression(exp.Hint, expressions=hints)
    3461
    3462    def _parse_hint(self) -> t.Optional[exp.Hint]:
    3463        if self._match(TokenType.HINT) and self._prev_comments:
    3464            return exp.maybe_parse(self._prev_comments[0], into=exp.Hint, dialect=self.dialect)
    3465
    3466        return None
    3467
    3468    def _parse_into(self) -> t.Optional[exp.Into]:
    3469        if not self._match(TokenType.INTO):
    3470            return None
    3471
    3472        temp = self._match(TokenType.TEMPORARY)
    3473        unlogged = self._match_text_seq("UNLOGGED")
    3474        self._match(TokenType.TABLE)
    3475
    3476        return self.expression(
    3477            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
    3478        )
    3479
    3480    def _parse_from(
    3481        self, joins: bool = False, skip_from_token: bool = False
    3482    ) -> t.Optional[exp.From]:
    3483        if not skip_from_token and not self._match(TokenType.FROM):
    3484            return None
    3485
    3486        return self.expression(
    3487            exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
    3488        )
    3489
    3490    def _parse_match_recognize_measure(self) -> exp.MatchRecognizeMeasure:
    3491        return self.expression(
    3492            exp.MatchRecognizeMeasure,
    3493            window_frame=self._match_texts(("FINAL", "RUNNING")) and self._prev.text.upper(),
    3494            this=self._parse_expression(),
    3495        )
    3496
    3497    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
    3498        if not self._match(TokenType.MATCH_RECOGNIZE):
    3499            return None
    3500
    3501        self._match_l_paren()
    3502
    3503        partition = self._parse_partition_by()
    3504        order = self._parse_order()
    3505
    3506        measures = (
    3507            self._parse_csv(self._parse_match_recognize_measure)
    3508            if self._match_text_seq("MEASURES")
    3509            else None
    3510        )
    3511
    3512        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
    3513            rows = exp.var("ONE ROW PER MATCH")
    3514        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
    3515            text = "ALL ROWS PER MATCH"
    3516            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
    3517                text += " SHOW EMPTY MATCHES"
    3518            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
    3519                text += " OMIT EMPTY MATCHES"
    3520            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
    3521                text += " WITH UNMATCHED ROWS"
    3522            rows = exp.var(text)
    3523        else:
    3524            rows = None
    3525
    3526        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
    3527            text = "AFTER MATCH SKIP"
    3528            if self._match_text_seq("PAST", "LAST", "ROW"):
    3529                text += " PAST LAST ROW"
    3530            elif self._match_text_seq("TO", "NEXT", "ROW"):
    3531                text += " TO NEXT ROW"
    3532            elif self._match_text_seq("TO", "FIRST"):
    3533                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
    3534            elif self._match_text_seq("TO", "LAST"):
    3535                text += f" TO LAST {self._advance_any().text}"  # type: ignore
    3536            after = exp.var(text)
    3537        else:
    3538            after = None
    3539
    3540        if self._match_text_seq("PATTERN"):
    3541            self._match_l_paren()
    3542
    3543            if not self._curr:
    3544                self.raise_error("Expecting )", self._curr)
    3545
    3546            paren = 1
    3547            start = self._curr
    3548
    3549            while self._curr and paren > 0:
    3550                if self._curr.token_type == TokenType.L_PAREN:
    3551                    paren += 1
    3552                if self._curr.token_type == TokenType.R_PAREN:
    3553                    paren -= 1
    3554
    3555                end = self._prev
    3556                self._advance()
    3557
    3558            if paren > 0:
    3559                self.raise_error("Expecting )", self._curr)
    3560
    3561            pattern = exp.var(self._find_sql(start, end))
    3562        else:
    3563            pattern = None
    3564
    3565        define = (
    3566            self._parse_csv(self._parse_name_as_expression)
    3567            if self._match_text_seq("DEFINE")
    3568            else None
    3569        )
    3570
    3571        self._match_r_paren()
    3572
    3573        return self.expression(
    3574            exp.MatchRecognize,
    3575            partition_by=partition,
    3576            order=order,
    3577            measures=measures,
    3578            rows=rows,
    3579            after=after,
    3580            pattern=pattern,
    3581            define=define,
    3582            alias=self._parse_table_alias(),
    3583        )
    3584
    3585    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
    3586        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
    3587        if not cross_apply and self._match_pair(TokenType.OUTER, TokenType.APPLY):
    3588            cross_apply = False
    3589
    3590        if cross_apply is not None:
    3591            this = self._parse_select(table=True)
    3592            view = None
    3593            outer = None
    3594        elif self._match(TokenType.LATERAL):
    3595            this = self._parse_select(table=True)
    3596            view = self._match(TokenType.VIEW)
    3597            outer = self._match(TokenType.OUTER)
    3598        else:
    3599            return None
    3600
    3601        if not this:
    3602            this = (
    3603                self._parse_unnest()
    3604                or self._parse_function()
    3605                or self._parse_id_var(any_token=False)
    3606            )
    3607
    3608            while self._match(TokenType.DOT):
    3609                this = exp.Dot(
    3610                    this=this,
    3611                    expression=self._parse_function() or self._parse_id_var(any_token=False),
    3612                )
    3613
    3614        ordinality: t.Optional[bool] = None
    3615
    3616        if view:
    3617            table = self._parse_id_var(any_token=False)
    3618            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
    3619            table_alias: t.Optional[exp.TableAlias] = self.expression(
    3620                exp.TableAlias, this=table, columns=columns
    3621            )
    3622        elif isinstance(this, (exp.Subquery, exp.Unnest)) and this.alias:
    3623            # We move the alias from the lateral's child node to the lateral itself
    3624            table_alias = this.args["alias"].pop()
    3625        else:
    3626            ordinality = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
    3627            table_alias = self._parse_table_alias()
    3628
    3629        return self.expression(
    3630            exp.Lateral,
    3631            this=this,
    3632            view=view,
    3633            outer=outer,
    3634            alias=table_alias,
    3635            cross_apply=cross_apply,
    3636            ordinality=ordinality,
    3637        )
    3638
    3639    def _parse_join_parts(
    3640        self,
    3641    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
    3642        return (
    3643            self._match_set(self.JOIN_METHODS) and self._prev,
    3644            self._match_set(self.JOIN_SIDES) and self._prev,
    3645            self._match_set(self.JOIN_KINDS) and self._prev,
    3646        )
    3647
    3648    def _parse_using_identifiers(self) -> t.List[exp.Expression]:
    3649        def _parse_column_as_identifier() -> t.Optional[exp.Expression]:
    3650            this = self._parse_column()
    3651            if isinstance(this, exp.Column):
    3652                return this.this
    3653            return this
    3654
    3655        return self._parse_wrapped_csv(_parse_column_as_identifier, optional=True)
    3656
    3657    def _parse_join(
    3658        self, skip_join_token: bool = False, parse_bracket: bool = False
    3659    ) -> t.Optional[exp.Join]:
    3660        if self._match(TokenType.COMMA):
    3661            table = self._try_parse(self._parse_table)
    3662            if table:
    3663                return self.expression(exp.Join, this=table)
    3664            return None
    3665
    3666        index = self._index
    3667        method, side, kind = self._parse_join_parts()
    3668        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
    3669        join = self._match(TokenType.JOIN) or (kind and kind.token_type == TokenType.STRAIGHT_JOIN)
    3670
    3671        if not skip_join_token and not join:
    3672            self._retreat(index)
    3673            kind = None
    3674            method = None
    3675            side = None
    3676
    3677        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
    3678        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
    3679
    3680        if not skip_join_token and not join and not outer_apply and not cross_apply:
    3681            return None
    3682
    3683        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table(parse_bracket=parse_bracket)}
    3684        if kind and kind.token_type == TokenType.ARRAY and self._match(TokenType.COMMA):
    3685            kwargs["expressions"] = self._parse_csv(
    3686                lambda: self._parse_table(parse_bracket=parse_bracket)
    3687            )
    3688
    3689        if method:
    3690            kwargs["method"] = method.text
    3691        if side:
    3692            kwargs["side"] = side.text
    3693        if kind:
    3694            kwargs["kind"] = kind.text
    3695        if hint:
    3696            kwargs["hint"] = hint
    3697
    3698        if self._match(TokenType.MATCH_CONDITION):
    3699            kwargs["match_condition"] = self._parse_wrapped(self._parse_comparison)
    3700
    3701        if self._match(TokenType.ON):
    3702            kwargs["on"] = self._parse_assignment()
    3703        elif self._match(TokenType.USING):
    3704            kwargs["using"] = self._parse_using_identifiers()
    3705        elif (
    3706            not (outer_apply or cross_apply)
    3707            and not isinstance(kwargs["this"], exp.Unnest)
    3708            and not (kind and kind.token_type in (TokenType.CROSS, TokenType.ARRAY))
    3709        ):
    3710            index = self._index
    3711            joins: t.Optional[list] = list(self._parse_joins())
    3712
    3713            if joins and self._match(TokenType.ON):
    3714                kwargs["on"] = self._parse_assignment()
    3715            elif joins and self._match(TokenType.USING):
    3716                kwargs["using"] = self._parse_using_identifiers()
    3717            else:
    3718                joins = None
    3719                self._retreat(index)
    3720
    3721            kwargs["this"].set("joins", joins if joins else None)
    3722
    3723        comments = [c for token in (method, side, kind) if token for c in token.comments]
    3724        return self.expression(exp.Join, comments=comments, **kwargs)
    3725
    3726    def _parse_opclass(self) -> t.Optional[exp.Expression]:
    3727        this = self._parse_assignment()
    3728
    3729        if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
    3730            return this
    3731
    3732        if not self._match_set(self.OPTYPE_FOLLOW_TOKENS, advance=False):
    3733            return self.expression(exp.Opclass, this=this, expression=self._parse_table_parts())
    3734
    3735        return this
    3736
    3737    def _parse_index_params(self) -> exp.IndexParameters:
    3738        using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
    3739
    3740        if self._match(TokenType.L_PAREN, advance=False):
    3741            columns = self._parse_wrapped_csv(self._parse_with_operator)
    3742        else:
    3743            columns = None
    3744
    3745        include = self._parse_wrapped_id_vars() if self._match_text_seq("INCLUDE") else None
    3746        partition_by = self._parse_partition_by()
    3747        with_storage = self._match(TokenType.WITH) and self._parse_wrapped_properties()
    3748        tablespace = (
    3749            self._parse_var(any_token=True)
    3750            if self._match_text_seq("USING", "INDEX", "TABLESPACE")
    3751            else None
    3752        )
    3753        where = self._parse_where()
    3754
    3755        on = self._parse_field() if self._match(TokenType.ON) else None
    3756
    3757        return self.expression(
    3758            exp.IndexParameters,
    3759            using=using,
    3760            columns=columns,
    3761            include=include,
    3762            partition_by=partition_by,
    3763            where=where,
    3764            with_storage=with_storage,
    3765            tablespace=tablespace,
    3766            on=on,
    3767        )
    3768
    3769    def _parse_index(
    3770        self, index: t.Optional[exp.Expression] = None, anonymous: bool = False
    3771    ) -> t.Optional[exp.Index]:
    3772        if index or anonymous:
    3773            unique = None
    3774            primary = None
    3775            amp = None
    3776
    3777            self._match(TokenType.ON)
    3778            self._match(TokenType.TABLE)  # hive
    3779            table = self._parse_table_parts(schema=True)
    3780        else:
    3781            unique = self._match(TokenType.UNIQUE)
    3782            primary = self._match_text_seq("PRIMARY")
    3783            amp = self._match_text_seq("AMP")
    3784
    3785            if not self._match(TokenType.INDEX):
    3786                return None
    3787
    3788            index = self._parse_id_var()
    3789            table = None
    3790
    3791        params = self._parse_index_params()
    3792
    3793        return self.expression(
    3794            exp.Index,
    3795            this=index,
    3796            table=table,
    3797            unique=unique,
    3798            primary=primary,
    3799            amp=amp,
    3800            params=params,
    3801        )
    3802
    3803    def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
    3804        hints: t.List[exp.Expression] = []
    3805        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
    3806            # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
    3807            hints.append(
    3808                self.expression(
    3809                    exp.WithTableHint,
    3810                    expressions=self._parse_csv(
    3811                        lambda: self._parse_function() or self._parse_var(any_token=True)
    3812                    ),
    3813                )
    3814            )
    3815            self._match_r_paren()
    3816        else:
    3817            # https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
    3818            while self._match_set(self.TABLE_INDEX_HINT_TOKENS):
    3819                hint = exp.IndexTableHint(this=self._prev.text.upper())
    3820
    3821                self._match_set((TokenType.INDEX, TokenType.KEY))
    3822                if self._match(TokenType.FOR):
    3823                    hint.set("target", self._advance_any() and self._prev.text.upper())
    3824
    3825                hint.set("expressions", self._parse_wrapped_id_vars())
    3826                hints.append(hint)
    3827
    3828        return hints or None
    3829
    3830    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
    3831        return (
    3832            (not schema and self._parse_function(optional_parens=False))
    3833            or self._parse_id_var(any_token=False)
    3834            or self._parse_string_as_identifier()
    3835            or self._parse_placeholder()
    3836        )
    3837
    3838    def _parse_table_parts(
    3839        self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
    3840    ) -> exp.Table:
    3841        catalog = None
    3842        db = None
    3843        table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
    3844
    3845        while self._match(TokenType.DOT):
    3846            if catalog:
    3847                # This allows nesting the table in arbitrarily many dot expressions if needed
    3848                table = self.expression(
    3849                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
    3850                )
    3851            else:
    3852                catalog = db
    3853                db = table
    3854                # "" used for tsql FROM a..b case
    3855                table = self._parse_table_part(schema=schema) or ""
    3856
    3857        if (
    3858            wildcard
    3859            and self._is_connected()
    3860            and (isinstance(table, exp.Identifier) or not table)
    3861            and self._match(TokenType.STAR)
    3862        ):
    3863            if isinstance(table, exp.Identifier):
    3864                table.args["this"] += "*"
    3865            else:
    3866                table = exp.Identifier(this="*")
    3867
    3868        # We bubble up comments from the Identifier to the Table
    3869        comments = table.pop_comments() if isinstance(table, exp.Expression) else None
    3870
    3871        if is_db_reference:
    3872            catalog = db
    3873            db = table
    3874            table = None
    3875
    3876        if not table and not is_db_reference:
    3877            self.raise_error(f"Expected table name but got {self._curr}")
    3878        if not db and is_db_reference:
    3879            self.raise_error(f"Expected database name but got {self._curr}")
    3880
    3881        table = self.expression(
    3882            exp.Table,
    3883            comments=comments,
    3884            this=table,
    3885            db=db,
    3886            catalog=catalog,
    3887        )
    3888
    3889        changes = self._parse_changes()
    3890        if changes:
    3891            table.set("changes", changes)
    3892
    3893        at_before = self._parse_historical_data()
    3894        if at_before:
    3895            table.set("when", at_before)
    3896
    3897        pivots = self._parse_pivots()
    3898        if pivots:
    3899            table.set("pivots", pivots)
    3900
    3901        return table
    3902
    3903    def _parse_table(
    3904        self,
    3905        schema: bool = False,
    3906        joins: bool = False,
    3907        alias_tokens: t.Optional[t.Collection[TokenType]] = None,
    3908        parse_bracket: bool = False,
    3909        is_db_reference: bool = False,
    3910        parse_partition: bool = False,
    3911    ) -> t.Optional[exp.Expression]:
    3912        lateral = self._parse_lateral()
    3913        if lateral:
    3914            return lateral
    3915
    3916        unnest = self._parse_unnest()
    3917        if unnest:
    3918            return unnest
    3919
    3920        values = self._parse_derived_table_values()
    3921        if values:
    3922            return values
    3923
    3924        subquery = self._parse_select(table=True)
    3925        if subquery:
    3926            if not subquery.args.get("pivots"):
    3927                subquery.set("pivots", self._parse_pivots())
    3928            return subquery
    3929
    3930        bracket = parse_bracket and self._parse_bracket(None)
    3931        bracket = self.expression(exp.Table, this=bracket) if bracket else None
    3932
    3933        rows_from = self._match_text_seq("ROWS", "FROM") and self._parse_wrapped_csv(
    3934            self._parse_table
    3935        )
    3936        rows_from = self.expression(exp.Table, rows_from=rows_from) if rows_from else None
    3937
    3938        only = self._match(TokenType.ONLY)
    3939
    3940        this = t.cast(
    3941            exp.Expression,
    3942            bracket
    3943            or rows_from
    3944            or self._parse_bracket(
    3945                self._parse_table_parts(schema=schema, is_db_reference=is_db_reference)
    3946            ),
    3947        )
    3948
    3949        if only:
    3950            this.set("only", only)
    3951
    3952        # Postgres supports a wildcard (table) suffix operator, which is a no-op in this context
    3953        self._match_text_seq("*")
    3954
    3955        parse_partition = parse_partition or self.SUPPORTS_PARTITION_SELECTION
    3956        if parse_partition and self._match(TokenType.PARTITION, advance=False):
    3957            this.set("partition", self._parse_partition())
    3958
    3959        if schema:
    3960            return self._parse_schema(this=this)
    3961
    3962        version = self._parse_version()
    3963
    3964        if version:
    3965            this.set("version", version)
    3966
    3967        if self.dialect.ALIAS_POST_TABLESAMPLE:
    3968            this.set("sample", self._parse_table_sample())
    3969
    3970        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
    3971        if alias:
    3972            this.set("alias", alias)
    3973
    3974        if isinstance(this, exp.Table) and self._match_text_seq("AT"):
    3975            return self.expression(
    3976                exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
    3977            )
    3978
    3979        this.set("hints", self._parse_table_hints())
    3980
    3981        if not this.args.get("pivots"):
    3982            this.set("pivots", self._parse_pivots())
    3983
    3984        if not self.dialect.ALIAS_POST_TABLESAMPLE:
    3985            this.set("sample", self._parse_table_sample())
    3986
    3987        if joins:
    3988            for join in self._parse_joins():
    3989                this.append("joins", join)
    3990
    3991        if self._match_pair(TokenType.WITH, TokenType.ORDINALITY):
    3992            this.set("ordinality", True)
    3993            this.set("alias", self._parse_table_alias())
    3994
    3995        return this
    3996
    3997    def _parse_version(self) -> t.Optional[exp.Version]:
    3998        if self._match(TokenType.TIMESTAMP_SNAPSHOT):
    3999            this = "TIMESTAMP"
    4000        elif self._match(TokenType.VERSION_SNAPSHOT):
    4001            this = "VERSION"
    4002        else:
    4003            return None
    4004
    4005        if self._match_set((TokenType.FROM, TokenType.BETWEEN)):
    4006            kind = self._prev.text.upper()
    4007            start = self._parse_bitwise()
    4008            self._match_texts(("TO", "AND"))
    4009            end = self._parse_bitwise()
    4010            expression: t.Optional[exp.Expression] = self.expression(
    4011                exp.Tuple, expressions=[start, end]
    4012            )
    4013        elif self._match_text_seq("CONTAINED", "IN"):
    4014            kind = "CONTAINED IN"
    4015            expression = self.expression(
    4016                exp.Tuple, expressions=self._parse_wrapped_csv(self._parse_bitwise)
    4017            )
    4018        elif self._match(TokenType.ALL):
    4019            kind = "ALL"
    4020            expression = None
    4021        else:
    4022            self._match_text_seq("AS", "OF")
    4023            kind = "AS OF"
    4024            expression = self._parse_type()
    4025
    4026        return self.expression(exp.Version, this=this, expression=expression, kind=kind)
    4027
    4028    def _parse_historical_data(self) -> t.Optional[exp.HistoricalData]:
    4029        # https://docs.snowflake.com/en/sql-reference/constructs/at-before
    4030        index = self._index
    4031        historical_data = None
    4032        if self._match_texts(self.HISTORICAL_DATA_PREFIX):
    4033            this = self._prev.text.upper()
    4034            kind = (
    4035                self._match(TokenType.L_PAREN)
    4036                and self._match_texts(self.HISTORICAL_DATA_KIND)
    4037                and self._prev.text.upper()
    4038            )
    4039            expression = self._match(TokenType.FARROW) and self._parse_bitwise()
    4040
    4041            if expression:
    4042                self._match_r_paren()
    4043                historical_data = self.expression(
    4044                    exp.HistoricalData, this=this, kind=kind, expression=expression
    4045                )
    4046            else:
    4047                self._retreat(index)
    4048
    4049        return historical_data
    4050
    4051    def _parse_changes(self) -> t.Optional[exp.Changes]:
    4052        if not self._match_text_seq("CHANGES", "(", "INFORMATION", "=>"):
    4053            return None
    4054
    4055        information = self._parse_var(any_token=True)
    4056        self._match_r_paren()
    4057
    4058        return self.expression(
    4059            exp.Changes,
    4060            information=information,
    4061            at_before=self._parse_historical_data(),
    4062            end=self._parse_historical_data(),
    4063        )
    4064
    4065    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
    4066        if not self._match(TokenType.UNNEST):
    4067            return None
    4068
    4069        expressions = self._parse_wrapped_csv(self._parse_equality)
    4070        offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
    4071
    4072        alias = self._parse_table_alias() if with_alias else None
    4073
    4074        if alias:
    4075            if self.dialect.UNNEST_COLUMN_ONLY:
    4076                if alias.args.get("columns"):
    4077                    self.raise_error("Unexpected extra column alias in unnest.")
    4078
    4079                alias.set("columns", [alias.this])
    4080                alias.set("this", None)
    4081
    4082            columns = alias.args.get("columns") or []
    4083            if offset and len(expressions) < len(columns):
    4084                offset = columns.pop()
    4085
    4086        if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
    4087            self._match(TokenType.ALIAS)
    4088            offset = self._parse_id_var(
    4089                any_token=False, tokens=self.UNNEST_OFFSET_ALIAS_TOKENS
    4090            ) or exp.to_identifier("offset")
    4091
    4092        return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
    4093
    4094    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
    4095        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
    4096        if not is_derived and not (
    4097            # ClickHouse's `FORMAT Values` is equivalent to `VALUES`
    4098            self._match_text_seq("VALUES") or self._match_text_seq("FORMAT", "VALUES")
    4099        ):
    4100            return None
    4101
    4102        expressions = self._parse_csv(self._parse_value)
    4103        alias = self._parse_table_alias()
    4104
    4105        if is_derived:
    4106            self._match_r_paren()
    4107
    4108        return self.expression(
    4109            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
    4110        )
    4111
    4112    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
    4113        if not self._match(TokenType.TABLE_SAMPLE) and not (
    4114            as_modifier and self._match_text_seq("USING", "SAMPLE")
    4115        ):
    4116            return None
    4117
    4118        bucket_numerator = None
    4119        bucket_denominator = None
    4120        bucket_field = None
    4121        percent = None
    4122        size = None
    4123        seed = None
    4124
    4125        method = self._parse_var(tokens=(TokenType.ROW,), upper=True)
    4126        matched_l_paren = self._match(TokenType.L_PAREN)
    4127
    4128        if self.TABLESAMPLE_CSV:
    4129            num = None
    4130            expressions = self._parse_csv(self._parse_primary)
    4131        else:
    4132            expressions = None
    4133            num = (
    4134                self._parse_factor()
    4135                if self._match(TokenType.NUMBER, advance=False)
    4136                else self._parse_primary() or self._parse_placeholder()
    4137            )
    4138
    4139        if self._match_text_seq("BUCKET"):
    4140            bucket_numerator = self._parse_number()
    4141            self._match_text_seq("OUT", "OF")
    4142            bucket_denominator = bucket_denominator = self._parse_number()
    4143            self._match(TokenType.ON)
    4144            bucket_field = self._parse_field()
    4145        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
    4146            percent = num
    4147        elif self._match(TokenType.ROWS) or not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
    4148            size = num
    4149        else:
    4150            percent = num
    4151
    4152        if matched_l_paren:
    4153            self._match_r_paren()
    4154
    4155        if self._match(TokenType.L_PAREN):
    4156            method = self._parse_var(upper=True)
    4157            seed = self._match(TokenType.COMMA) and self._parse_number()
    4158            self._match_r_paren()
    4159        elif self._match_texts(("SEED", "REPEATABLE")):
    4160            seed = self._parse_wrapped(self._parse_number)
    4161
    4162        if not method and self.DEFAULT_SAMPLING_METHOD:
    4163            method = exp.var(self.DEFAULT_SAMPLING_METHOD)
    4164
    4165        return self.expression(
    4166            exp.TableSample,
    4167            expressions=expressions,
    4168            method=method,
    4169            bucket_numerator=bucket_numerator,
    4170            bucket_denominator=bucket_denominator,
    4171            bucket_field=bucket_field,
    4172            percent=percent,
    4173            size=size,
    4174            seed=seed,
    4175        )
    4176
    4177    def _parse_pivots(self) -> t.Optional[t.List[exp.Pivot]]:
    4178        return list(iter(self._parse_pivot, None)) or None
    4179
    4180    def _parse_joins(self) -> t.Iterator[exp.Join]:
    4181        return iter(self._parse_join, None)
    4182
    4183    def _parse_unpivot_columns(self) -> t.Optional[exp.UnpivotColumns]:
    4184        if not self._match(TokenType.INTO):
    4185            return None
    4186
    4187        return self.expression(
    4188            exp.UnpivotColumns,
    4189            this=self._match_text_seq("NAME") and self._parse_column(),
    4190            expressions=self._match_text_seq("VALUE") and self._parse_csv(self._parse_column),
    4191        )
    4192
    4193    # https://duckdb.org/docs/sql/statements/pivot
    4194    def _parse_simplified_pivot(self, is_unpivot: t.Optional[bool] = None) -> exp.Pivot:
    4195        def _parse_on() -> t.Optional[exp.Expression]:
    4196            this = self._parse_bitwise()
    4197
    4198            if self._match(TokenType.IN):
    4199                # PIVOT ... ON col IN (row_val1, row_val2)
    4200                return self._parse_in(this)
    4201            if self._match(TokenType.ALIAS, advance=False):
    4202                # UNPIVOT ... ON (col1, col2, col3) AS row_val
    4203                return self._parse_alias(this)
    4204
    4205            return this
    4206
    4207        this = self._parse_table()
    4208        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
    4209        into = self._parse_unpivot_columns()
    4210        using = self._match(TokenType.USING) and self._parse_csv(
    4211            lambda: self._parse_alias(self._parse_function())
    4212        )
    4213        group = self._parse_group()
    4214
    4215        return self.expression(
    4216            exp.Pivot,
    4217            this=this,
    4218            expressions=expressions,
    4219            using=using,
    4220            group=group,
    4221            unpivot=is_unpivot,
    4222            into=into,
    4223        )
    4224
    4225    def _parse_pivot_in(self) -> exp.In:
    4226        def _parse_aliased_expression() -> t.Optional[exp.Expression]:
    4227            this = self._parse_select_or_expression()
    4228
    4229            self._match(TokenType.ALIAS)
    4230            alias = self._parse_bitwise()
    4231            if alias:
    4232                if isinstance(alias, exp.Column) and not alias.db:
    4233                    alias = alias.this
    4234                return self.expression(exp.PivotAlias, this=this, alias=alias)
    4235
    4236            return this
    4237
    4238        value = self._parse_column()
    4239
    4240        if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
    4241            self.raise_error("Expecting IN (")
    4242
    4243        if self._match(TokenType.ANY):
    4244            exprs: t.List[exp.Expression] = ensure_list(exp.PivotAny(this=self._parse_order()))
    4245        else:
    4246            exprs = self._parse_csv(_parse_aliased_expression)
    4247
    4248        self._match_r_paren()
    4249        return self.expression(exp.In, this=value, expressions=exprs)
    4250
    4251    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
    4252        index = self._index
    4253        include_nulls = None
    4254
    4255        if self._match(TokenType.PIVOT):
    4256            unpivot = False
    4257        elif self._match(TokenType.UNPIVOT):
    4258            unpivot = True
    4259
    4260            # https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
    4261            if self._match_text_seq("INCLUDE", "NULLS"):
    4262                include_nulls = True
    4263            elif self._match_text_seq("EXCLUDE", "NULLS"):
    4264                include_nulls = False
    4265        else:
    4266            return None
    4267
    4268        expressions = []
    4269
    4270        if not self._match(TokenType.L_PAREN):
    4271            self._retreat(index)
    4272            return None
    4273
    4274        if unpivot:
    4275            expressions = self._parse_csv(self._parse_column)
    4276        else:
    4277            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
    4278
    4279        if not expressions:
    4280            self.raise_error("Failed to parse PIVOT's aggregation list")
    4281
    4282        if not self._match(TokenType.FOR):
    4283            self.raise_error("Expecting FOR")
    4284
    4285        fields = []
    4286        while True:
    4287            field = self._try_parse(self._parse_pivot_in)
    4288            if not field:
    4289                break
    4290            fields.append(field)
    4291
    4292        default_on_null = self._match_text_seq("DEFAULT", "ON", "NULL") and self._parse_wrapped(
    4293            self._parse_bitwise
    4294        )
    4295
    4296        group = self._parse_group()
    4297
    4298        self._match_r_paren()
    4299
    4300        pivot = self.expression(
    4301            exp.Pivot,
    4302            expressions=expressions,
    4303            fields=fields,
    4304            unpivot=unpivot,
    4305            include_nulls=include_nulls,
    4306            default_on_null=default_on_null,
    4307            group=group,
    4308        )
    4309
    4310        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
    4311            pivot.set("alias", self._parse_table_alias())
    4312
    4313        if not unpivot:
    4314            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
    4315
    4316            columns: t.List[exp.Expression] = []
    4317            all_fields = []
    4318            for pivot_field in pivot.fields:
    4319                pivot_field_expressions = pivot_field.expressions
    4320
    4321                # The `PivotAny` expression corresponds to `ANY ORDER BY <column>`; we can't infer in this case.
    4322                if isinstance(seq_get(pivot_field_expressions, 0), exp.PivotAny):
    4323                    continue
    4324
    4325                all_fields.append(
    4326                    [
    4327                        fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
    4328                        for fld in pivot_field_expressions
    4329                    ]
    4330                )
    4331
    4332            if all_fields:
    4333                if names:
    4334                    all_fields.append(names)
    4335
    4336                # Generate all possible combinations of the pivot columns
    4337                # e.g PIVOT(sum(...) as total FOR year IN (2000, 2010) FOR country IN ('NL', 'US'))
    4338                # generates the product between [[2000, 2010], ['NL', 'US'], ['total']]
    4339                for fld_parts_tuple in itertools.product(*all_fields):
    4340                    fld_parts = list(fld_parts_tuple)
    4341
    4342                    if names and self.PREFIXED_PIVOT_COLUMNS:
    4343                        # Move the "name" to the front of the list
    4344                        fld_parts.insert(0, fld_parts.pop(-1))
    4345
    4346                    columns.append(exp.to_identifier("_".join(fld_parts)))
    4347
    4348            pivot.set("columns", columns)
    4349
    4350        return pivot
    4351
    4352    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
    4353        return [agg.alias for agg in aggregations if agg.alias]
    4354
    4355    def _parse_prewhere(self, skip_where_token: bool = False) -> t.Optional[exp.PreWhere]:
    4356        if not skip_where_token and not self._match(TokenType.PREWHERE):
    4357            return None
    4358
    4359        return self.expression(
    4360            exp.PreWhere, comments=self._prev_comments, this=self._parse_assignment()
    4361        )
    4362
    4363    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
    4364        if not skip_where_token and not self._match(TokenType.WHERE):
    4365            return None
    4366
    4367        return self.expression(
    4368            exp.Where, comments=self._prev_comments, this=self._parse_assignment()
    4369        )
    4370
    4371    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
    4372        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
    4373            return None
    4374
    4375        elements: t.Dict[str, t.Any] = defaultdict(list)
    4376
    4377        if self._match(TokenType.ALL):
    4378            elements["all"] = True
    4379        elif self._match(TokenType.DISTINCT):
    4380            elements["all"] = False
    4381
    4382        while True:
    4383            index = self._index
    4384
    4385            elements["expressions"].extend(
    4386                self._parse_csv(
    4387                    lambda: None
    4388                    if self._match_set((TokenType.CUBE, TokenType.ROLLUP), advance=False)
    4389                    else self._parse_assignment()
    4390                )
    4391            )
    4392
    4393            before_with_index = self._index
    4394            with_prefix = self._match(TokenType.WITH)
    4395
    4396            if self._match(TokenType.ROLLUP):
    4397                elements["rollup"].append(
    4398                    self._parse_cube_or_rollup(exp.Rollup, with_prefix=with_prefix)
    4399                )
    4400            elif self._match(TokenType.CUBE):
    4401                elements["cube"].append(
    4402                    self._parse_cube_or_rollup(exp.Cube, with_prefix=with_prefix)
    4403                )
    4404            elif self._match(TokenType.GROUPING_SETS):
    4405                elements["grouping_sets"].append(
    4406                    self.expression(
    4407                        exp.GroupingSets,
    4408                        expressions=self._parse_wrapped_csv(self._parse_grouping_set),
    4409                    )
    4410                )
    4411            elif self._match_text_seq("TOTALS"):
    4412                elements["totals"] = True  # type: ignore
    4413
    4414            if before_with_index <= self._index <= before_with_index + 1:
    4415                self._retreat(before_with_index)
    4416                break
    4417
    4418            if index == self._index:
    4419                break
    4420
    4421        return self.expression(exp.Group, **elements)  # type: ignore
    4422
    4423    def _parse_cube_or_rollup(self, kind: t.Type[E], with_prefix: bool = False) -> E:
    4424        return self.expression(
    4425            kind, expressions=[] if with_prefix else self._parse_wrapped_csv(self._parse_column)
    4426        )
    4427
    4428    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
    4429        if self._match(TokenType.L_PAREN):
    4430            grouping_set = self._parse_csv(self._parse_column)
    4431            self._match_r_paren()
    4432            return self.expression(exp.Tuple, expressions=grouping_set)
    4433
    4434        return self._parse_column()
    4435
    4436    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
    4437        if not skip_having_token and not self._match(TokenType.HAVING):
    4438            return None
    4439        return self.expression(exp.Having, this=self._parse_assignment())
    4440
    4441    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
    4442        if not self._match(TokenType.QUALIFY):
    4443            return None
    4444        return self.expression(exp.Qualify, this=self._parse_assignment())
    4445
    4446    def _parse_connect(self, skip_start_token: bool = False) -> t.Optional[exp.Connect]:
    4447        if skip_start_token:
    4448            start = None
    4449        elif self._match(TokenType.START_WITH):
    4450            start = self._parse_assignment()
    4451        else:
    4452            return None
    4453
    4454        self._match(TokenType.CONNECT_BY)
    4455        nocycle = self._match_text_seq("NOCYCLE")
    4456        self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
    4457            exp.Prior, this=self._parse_bitwise()
    4458        )
    4459        connect = self._parse_assignment()
    4460        self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
    4461
    4462        if not start and self._match(TokenType.START_WITH):
    4463            start = self._parse_assignment()
    4464
    4465        return self.expression(exp.Connect, start=start, connect=connect, nocycle=nocycle)
    4466
    4467    def _parse_name_as_expression(self) -> t.Optional[exp.Expression]:
    4468        this = self._parse_id_var(any_token=True)
    4469        if self._match(TokenType.ALIAS):
    4470            this = self.expression(exp.Alias, alias=this, this=self._parse_assignment())
    4471        return this
    4472
    4473    def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
    4474        if self._match_text_seq("INTERPOLATE"):
    4475            return self._parse_wrapped_csv(self._parse_name_as_expression)
    4476        return None
    4477
    4478    def _parse_order(
    4479        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
    4480    ) -> t.Optional[exp.Expression]:
    4481        siblings = None
    4482        if not skip_order_token and not self._match(TokenType.ORDER_BY):
    4483            if not self._match(TokenType.ORDER_SIBLINGS_BY):
    4484                return this
    4485
    4486            siblings = True
    4487
    4488        return self.expression(
    4489            exp.Order,
    4490            this=this,
    4491            expressions=self._parse_csv(self._parse_ordered),
    4492            siblings=siblings,
    4493        )
    4494
    4495    def _parse_sort(self, exp_class: t.Type[E], token: TokenType) -> t.Optional[E]:
    4496        if not self._match(token):
    4497            return None
    4498        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
    4499
    4500    def _parse_ordered(
    4501        self, parse_method: t.Optional[t.Callable] = None
    4502    ) -> t.Optional[exp.Ordered]:
    4503        this = parse_method() if parse_method else self._parse_assignment()
    4504        if not this:
    4505            return None
    4506
    4507        if this.name.upper() == "ALL" and self.dialect.SUPPORTS_ORDER_BY_ALL:
    4508            this = exp.var("ALL")
    4509
    4510        asc = self._match(TokenType.ASC)
    4511        desc = self._match(TokenType.DESC) or (asc and False)
    4512
    4513        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
    4514        is_nulls_last = self._match_text_seq("NULLS", "LAST")
    4515
    4516        nulls_first = is_nulls_first or False
    4517        explicitly_null_ordered = is_nulls_first or is_nulls_last
    4518
    4519        if (
    4520            not explicitly_null_ordered
    4521            and (
    4522                (not desc and self.dialect.NULL_ORDERING == "nulls_are_small")
    4523                or (desc and self.dialect.NULL_ORDERING != "nulls_are_small")
    4524            )
    4525            and self.dialect.NULL_ORDERING != "nulls_are_last"
    4526        ):
    4527            nulls_first = True
    4528
    4529        if self._match_text_seq("WITH", "FILL"):
    4530            with_fill = self.expression(
    4531                exp.WithFill,
    4532                **{  # type: ignore
    4533                    "from": self._match(TokenType.FROM) and self._parse_bitwise(),
    4534                    "to": self._match_text_seq("TO") and self._parse_bitwise(),
    4535                    "step": self._match_text_seq("STEP") and self._parse_bitwise(),
    4536                    "interpolate": self._parse_interpolate(),
    4537                },
    4538            )
    4539        else:
    4540            with_fill = None
    4541
    4542        return self.expression(
    4543            exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
    4544        )
    4545
    4546    def _parse_limit_options(self) -> exp.LimitOptions:
    4547        percent = self._match(TokenType.PERCENT)
    4548        rows = self._match_set((TokenType.ROW, TokenType.ROWS))
    4549        self._match_text_seq("ONLY")
    4550        with_ties = self._match_text_seq("WITH", "TIES")
    4551        return self.expression(exp.LimitOptions, percent=percent, rows=rows, with_ties=with_ties)
    4552
    4553    def _parse_limit(
    4554        self,
    4555        this: t.Optional[exp.Expression] = None,
    4556        top: bool = False,
    4557        skip_limit_token: bool = False,
    4558    ) -> t.Optional[exp.Expression]:
    4559        if skip_limit_token or self._match(TokenType.TOP if top else TokenType.LIMIT):
    4560            comments = self._prev_comments
    4561            if top:
    4562                limit_paren = self._match(TokenType.L_PAREN)
    4563                expression = self._parse_term() if limit_paren else self._parse_number()
    4564
    4565                if limit_paren:
    4566                    self._match_r_paren()
    4567
    4568                limit_options = self._parse_limit_options()
    4569            else:
    4570                limit_options = None
    4571                expression = self._parse_term()
    4572
    4573            if self._match(TokenType.COMMA):
    4574                offset = expression
    4575                expression = self._parse_term()
    4576            else:
    4577                offset = None
    4578
    4579            limit_exp = self.expression(
    4580                exp.Limit,
    4581                this=this,
    4582                expression=expression,
    4583                offset=offset,
    4584                comments=comments,
    4585                limit_options=limit_options,
    4586                expressions=self._parse_limit_by(),
    4587            )
    4588
    4589            return limit_exp
    4590
    4591        if self._match(TokenType.FETCH):
    4592            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
    4593            direction = self._prev.text.upper() if direction else "FIRST"
    4594
    4595            count = self._parse_field(tokens=self.FETCH_TOKENS)
    4596
    4597            return self.expression(
    4598                exp.Fetch,
    4599                direction=direction,
    4600                count=count,
    4601                limit_options=self._parse_limit_options(),
    4602            )
    4603
    4604        return this
    4605
    4606    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    4607        if not self._match(TokenType.OFFSET):
    4608            return this
    4609
    4610        count = self._parse_term()
    4611        self._match_set((TokenType.ROW, TokenType.ROWS))
    4612
    4613        return self.expression(
    4614            exp.Offset, this=this, expression=count, expressions=self._parse_limit_by()
    4615        )
    4616
    4617    def _can_parse_limit_or_offset(self) -> bool:
    4618        if not self._match_set(self.AMBIGUOUS_ALIAS_TOKENS, advance=False):
    4619            return False
    4620
    4621        index = self._index
    4622        result = bool(
    4623            self._try_parse(self._parse_limit, retreat=True)
    4624            or self._try_parse(self._parse_offset, retreat=True)
    4625        )
    4626        self._retreat(index)
    4627        return result
    4628
    4629    def _parse_limit_by(self) -> t.Optional[t.List[exp.Expression]]:
    4630        return self._match_text_seq("BY") and self._parse_csv(self._parse_bitwise)
    4631
    4632    def _parse_locks(self) -> t.List[exp.Lock]:
    4633        locks = []
    4634        while True:
    4635            if self._match_text_seq("FOR", "UPDATE"):
    4636                update = True
    4637            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
    4638                "LOCK", "IN", "SHARE", "MODE"
    4639            ):
    4640                update = False
    4641            else:
    4642                break
    4643
    4644            expressions = None
    4645            if self._match_text_seq("OF"):
    4646                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
    4647
    4648            wait: t.Optional[bool | exp.Expression] = None
    4649            if self._match_text_seq("NOWAIT"):
    4650                wait = True
    4651            elif self._match_text_seq("WAIT"):
    4652                wait = self._parse_primary()
    4653            elif self._match_text_seq("SKIP", "LOCKED"):
    4654                wait = False
    4655
    4656            locks.append(
    4657                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
    4658            )
    4659
    4660        return locks
    4661
    4662    def parse_set_operation(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4663        start = self._index
    4664        _, side_token, kind_token = self._parse_join_parts()
    4665
    4666        side = side_token.text if side_token else None
    4667        kind = kind_token.text if kind_token else None
    4668
    4669        if not self._match_set(self.SET_OPERATIONS):
    4670            self._retreat(start)
    4671            return None
    4672
    4673        token_type = self._prev.token_type
    4674
    4675        if token_type == TokenType.UNION:
    4676            operation: t.Type[exp.SetOperation] = exp.Union
    4677        elif token_type == TokenType.EXCEPT:
    4678            operation = exp.Except
    4679        else:
    4680            operation = exp.Intersect
    4681
    4682        comments = self._prev.comments
    4683
    4684        if self._match(TokenType.DISTINCT):
    4685            distinct: t.Optional[bool] = True
    4686        elif self._match(TokenType.ALL):
    4687            distinct = False
    4688        else:
    4689            distinct = self.dialect.SET_OP_DISTINCT_BY_DEFAULT[operation]
    4690            if distinct is None:
    4691                self.raise_error(f"Expected DISTINCT or ALL for {operation.__name__}")
    4692
    4693        by_name = self._match_text_seq("BY", "NAME") or self._match_text_seq(
    4694            "STRICT", "CORRESPONDING"
    4695        )
    4696        if self._match_text_seq("CORRESPONDING"):
    4697            by_name = True
    4698            if not side and not kind:
    4699                kind = "INNER"
    4700
    4701        on_column_list = None
    4702        if by_name and self._match_texts(("ON", "BY")):
    4703            on_column_list = self._parse_wrapped_csv(self._parse_column)
    4704
    4705        expression = self._parse_select(nested=True, parse_set_operation=False)
    4706
    4707        return self.expression(
    4708            operation,
    4709            comments=comments,
    4710            this=this,
    4711            distinct=distinct,
    4712            by_name=by_name,
    4713            expression=expression,
    4714            side=side,
    4715            kind=kind,
    4716            on=on_column_list,
    4717        )
    4718
    4719    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4720        while True:
    4721            setop = self.parse_set_operation(this)
    4722            if not setop:
    4723                break
    4724            this = setop
    4725
    4726        if isinstance(this, exp.SetOperation) and self.MODIFIERS_ATTACHED_TO_SET_OP:
    4727            expression = this.expression
    4728
    4729            if expression:
    4730                for arg in self.SET_OP_MODIFIERS:
    4731                    expr = expression.args.get(arg)
    4732                    if expr:
    4733                        this.set(arg, expr.pop())
    4734
    4735        return this
    4736
    4737    def _parse_expression(self) -> t.Optional[exp.Expression]:
    4738        return self._parse_alias(self._parse_assignment())
    4739
    4740    def _parse_assignment(self) -> t.Optional[exp.Expression]:
    4741        this = self._parse_disjunction()
    4742        if not this and self._next and self._next.token_type in self.ASSIGNMENT:
    4743            # This allows us to parse <non-identifier token> := <expr>
    4744            this = exp.column(
    4745                t.cast(str, self._advance_any(ignore_reserved=True) and self._prev.text)
    4746            )
    4747
    4748        while self._match_set(self.ASSIGNMENT):
    4749            if isinstance(this, exp.Column) and len(this.parts) == 1:
    4750                this = this.this
    4751
    4752            this = self.expression(
    4753                self.ASSIGNMENT[self._prev.token_type],
    4754                this=this,
    4755                comments=self._prev_comments,
    4756                expression=self._parse_assignment(),
    4757            )
    4758
    4759        return this
    4760
    4761    def _parse_disjunction(self) -> t.Optional[exp.Expression]:
    4762        return self._parse_tokens(self._parse_conjunction, self.DISJUNCTION)
    4763
    4764    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
    4765        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
    4766
    4767    def _parse_equality(self) -> t.Optional[exp.Expression]:
    4768        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
    4769
    4770    def _parse_comparison(self) -> t.Optional[exp.Expression]:
    4771        return self._parse_tokens(self._parse_range, self.COMPARISON)
    4772
    4773    def _parse_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    4774        this = this or self._parse_bitwise()
    4775        negate = self._match(TokenType.NOT)
    4776
    4777        if self._match_set(self.RANGE_PARSERS):
    4778            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
    4779            if not expression:
    4780                return this
    4781
    4782            this = expression
    4783        elif self._match(TokenType.ISNULL):
    4784            this = self.expression(exp.Is, this=this, expression=exp.Null())
    4785
    4786        # Postgres supports ISNULL and NOTNULL for conditions.
    4787        # https://blog.andreiavram.ro/postgresql-null-composite-type/
    4788        if self._match(TokenType.NOTNULL):
    4789            this = self.expression(exp.Is, this=this, expression=exp.Null())
    4790            this = self.expression(exp.Not, this=this)
    4791
    4792        if negate:
    4793            this = self._negate_range(this)
    4794
    4795        if self._match(TokenType.IS):
    4796            this = self._parse_is(this)
    4797
    4798        return this
    4799
    4800    def _negate_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    4801        if not this:
    4802            return this
    4803
    4804        return self.expression(exp.Not, this=this)
    4805
    4806    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4807        index = self._index - 1
    4808        negate = self._match(TokenType.NOT)
    4809
    4810        if self._match_text_seq("DISTINCT", "FROM"):
    4811            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
    4812            return self.expression(klass, this=this, expression=self._parse_bitwise())
    4813
    4814        if self._match(TokenType.JSON):
    4815            kind = self._match_texts(self.IS_JSON_PREDICATE_KIND) and self._prev.text.upper()
    4816
    4817            if self._match_text_seq("WITH"):
    4818                _with = True
    4819            elif self._match_text_seq("WITHOUT"):
    4820                _with = False
    4821            else:
    4822                _with = None
    4823
    4824            unique = self._match(TokenType.UNIQUE)
    4825            self._match_text_seq("KEYS")
    4826            expression: t.Optional[exp.Expression] = self.expression(
    4827                exp.JSON, **{"this": kind, "with": _with, "unique": unique}
    4828            )
    4829        else:
    4830            expression = self._parse_primary() or self._parse_null()
    4831            if not expression:
    4832                self._retreat(index)
    4833                return None
    4834
    4835        this = self.expression(exp.Is, this=this, expression=expression)
    4836        return self.expression(exp.Not, this=this) if negate else this
    4837
    4838    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
    4839        unnest = self._parse_unnest(with_alias=False)
    4840        if unnest:
    4841            this = self.expression(exp.In, this=this, unnest=unnest)
    4842        elif self._match_set((TokenType.L_PAREN, TokenType.L_BRACKET)):
    4843            matched_l_paren = self._prev.token_type == TokenType.L_PAREN
    4844            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
    4845
    4846            if len(expressions) == 1 and isinstance(expressions[0], exp.Query):
    4847                this = self.expression(exp.In, this=this, query=expressions[0].subquery(copy=False))
    4848            else:
    4849                this = self.expression(exp.In, this=this, expressions=expressions)
    4850
    4851            if matched_l_paren:
    4852                self._match_r_paren(this)
    4853            elif not self._match(TokenType.R_BRACKET, expression=this):
    4854                self.raise_error("Expecting ]")
    4855        else:
    4856            this = self.expression(exp.In, this=this, field=self._parse_column())
    4857
    4858        return this
    4859
    4860    def _parse_between(self, this: t.Optional[exp.Expression]) -> exp.Between:
    4861        low = self._parse_bitwise()
    4862        self._match(TokenType.AND)
    4863        high = self._parse_bitwise()
    4864        return self.expression(exp.Between, this=this, low=low, high=high)
    4865
    4866    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4867        if not self._match(TokenType.ESCAPE):
    4868            return this
    4869        return self.expression(exp.Escape, this=this, expression=self._parse_string())
    4870
    4871    def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Add | exp.Interval]:
    4872        index = self._index
    4873
    4874        if not self._match(TokenType.INTERVAL) and match_interval:
    4875            return None
    4876
    4877        if self._match(TokenType.STRING, advance=False):
    4878            this = self._parse_primary()
    4879        else:
    4880            this = self._parse_term()
    4881
    4882        if not this or (
    4883            isinstance(this, exp.Column)
    4884            and not this.table
    4885            and not this.this.quoted
    4886            and this.name.upper() == "IS"
    4887        ):
    4888            self._retreat(index)
    4889            return None
    4890
    4891        unit = self._parse_function() or (
    4892            not self._match(TokenType.ALIAS, advance=False)
    4893            and self._parse_var(any_token=True, upper=True)
    4894        )
    4895
    4896        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
    4897        # each INTERVAL expression into this canonical form so it's easy to transpile
    4898        if this and this.is_number:
    4899            this = exp.Literal.string(this.to_py())
    4900        elif this and this.is_string:
    4901            parts = exp.INTERVAL_STRING_RE.findall(this.name)
    4902            if parts and unit:
    4903                # Unconsume the eagerly-parsed unit, since the real unit was part of the string
    4904                unit = None
    4905                self._retreat(self._index - 1)
    4906
    4907            if len(parts) == 1:
    4908                this = exp.Literal.string(parts[0][0])
    4909                unit = self.expression(exp.Var, this=parts[0][1].upper())
    4910        if self.INTERVAL_SPANS and self._match_text_seq("TO"):
    4911            unit = self.expression(
    4912                exp.IntervalSpan, this=unit, expression=self._parse_var(any_token=True, upper=True)
    4913            )
    4914
    4915        interval = self.expression(exp.Interval, this=this, unit=unit)
    4916
    4917        index = self._index
    4918        self._match(TokenType.PLUS)
    4919
    4920        # Convert INTERVAL 'val_1' unit_1 [+] ... [+] 'val_n' unit_n into a sum of intervals
    4921        if self._match_set((TokenType.STRING, TokenType.NUMBER), advance=False):
    4922            return self.expression(
    4923                exp.Add, this=interval, expression=self._parse_interval(match_interval=False)
    4924            )
    4925
    4926        self._retreat(index)
    4927        return interval
    4928
    4929    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
    4930        this = self._parse_term()
    4931
    4932        while True:
    4933            if self._match_set(self.BITWISE):
    4934                this = self.expression(
    4935                    self.BITWISE[self._prev.token_type],
    4936                    this=this,
    4937                    expression=self._parse_term(),
    4938                )
    4939            elif self.dialect.DPIPE_IS_STRING_CONCAT and self._match(TokenType.DPIPE):
    4940                this = self.expression(
    4941                    exp.DPipe,
    4942                    this=this,
    4943                    expression=self._parse_term(),
    4944                    safe=not self.dialect.STRICT_STRING_CONCAT,
    4945                )
    4946            elif self._match(TokenType.DQMARK):
    4947                this = self.expression(
    4948                    exp.Coalesce, this=this, expressions=ensure_list(self._parse_term())
    4949                )
    4950            elif self._match_pair(TokenType.LT, TokenType.LT):
    4951                this = self.expression(
    4952                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
    4953                )
    4954            elif self._match_pair(TokenType.GT, TokenType.GT):
    4955                this = self.expression(
    4956                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
    4957                )
    4958            else:
    4959                break
    4960
    4961        return this
    4962
    4963    def _parse_term(self) -> t.Optional[exp.Expression]:
    4964        this = self._parse_factor()
    4965
    4966        while self._match_set(self.TERM):
    4967            klass = self.TERM[self._prev.token_type]
    4968            comments = self._prev_comments
    4969            expression = self._parse_factor()
    4970
    4971            this = self.expression(klass, this=this, comments=comments, expression=expression)
    4972
    4973            if isinstance(this, exp.Collate):
    4974                expr = this.expression
    4975
    4976                # Preserve collations such as pg_catalog."default" (Postgres) as columns, otherwise
    4977                # fallback to Identifier / Var
    4978                if isinstance(expr, exp.Column) and len(expr.parts) == 1:
    4979                    ident = expr.this
    4980                    if isinstance(ident, exp.Identifier):
    4981                        this.set("expression", ident if ident.quoted else exp.var(ident.name))
    4982
    4983        return this
    4984
    4985    def _parse_factor(self) -> t.Optional[exp.Expression]:
    4986        parse_method = self._parse_exponent if self.EXPONENT else self._parse_unary
    4987        this = parse_method()
    4988
    4989        while self._match_set(self.FACTOR):
    4990            klass = self.FACTOR[self._prev.token_type]
    4991            comments = self._prev_comments
    4992            expression = parse_method()
    4993
    4994            if not expression and klass is exp.IntDiv and self._prev.text.isalpha():
    4995                self._retreat(self._index - 1)
    4996                return this
    4997
    4998            this = self.expression(klass, this=this, comments=comments, expression=expression)
    4999
    5000            if isinstance(this, exp.Div):
    5001                this.args["typed"] = self.dialect.TYPED_DIVISION
    5002                this.args["safe"] = self.dialect.SAFE_DIVISION
    5003
    5004        return this
    5005
    5006    def _parse_exponent(self) -> t.Optional[exp.Expression]:
    5007        return self._parse_tokens(self._parse_unary, self.EXPONENT)
    5008
    5009    def _parse_unary(self) -> t.Optional[exp.Expression]:
    5010        if self._match_set(self.UNARY_PARSERS):
    5011            return self.UNARY_PARSERS[self._prev.token_type](self)
    5012        return self._parse_at_time_zone(self._parse_type())
    5013
    5014    def _parse_type(
    5015        self, parse_interval: bool = True, fallback_to_identifier: bool = False
    5016    ) -> t.Optional[exp.Expression]:
    5017        interval = parse_interval and self._parse_interval()
    5018        if interval:
    5019            return interval
    5020
    5021        index = self._index
    5022        data_type = self._parse_types(check_func=True, allow_identifiers=False)
    5023
    5024        # parse_types() returns a Cast if we parsed BQ's inline constructor <type>(<values>) e.g.
    5025        # STRUCT<a INT, b STRING>(1, 'foo'), which is canonicalized to CAST(<values> AS <type>)
    5026        if isinstance(data_type, exp.Cast):
    5027            # This constructor can contain ops directly after it, for instance struct unnesting:
    5028            # STRUCT<a INT, b STRING>(1, 'foo').* --> CAST(STRUCT(1, 'foo') AS STRUCT<a iNT, b STRING).*
    5029            return self._parse_column_ops(data_type)
    5030
    5031        if data_type:
    5032            index2 = self._index
    5033            this = self._parse_primary()
    5034
    5035            if isinstance(this, exp.Literal):
    5036                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
    5037                if parser:
    5038                    return parser(self, this, data_type)
    5039
    5040                return self.expression(exp.Cast, this=this, to=data_type)
    5041
    5042            # The expressions arg gets set by the parser when we have something like DECIMAL(38, 0)
    5043            # in the input SQL. In that case, we'll produce these tokens: DECIMAL ( 38 , 0 )
    5044            #
    5045            # If the index difference here is greater than 1, that means the parser itself must have
    5046            # consumed additional tokens such as the DECIMAL scale and precision in the above example.
    5047            #
    5048            # If it's not greater than 1, then it must be 1, because we've consumed at least the type
    5049            # keyword, meaning that the expressions arg of the DataType must have gotten set by a
    5050            # callable in the TYPE_CONVERTERS mapping. For example, Snowflake converts DECIMAL to
    5051            # DECIMAL(38, 0)) in order to facilitate the data type's transpilation.
    5052            #
    5053            # In these cases, we don't really want to return the converted type, but instead retreat
    5054            # and try to parse a Column or Identifier in the section below.
    5055            if data_type.expressions and index2 - index > 1:
    5056                self._retreat(index2)
    5057                return self._parse_column_ops(data_type)
    5058
    5059            self._retreat(index)
    5060
    5061        if fallback_to_identifier:
    5062            return self._parse_id_var()
    5063
    5064        this = self._parse_column()
    5065        return this and self._parse_column_ops(this)
    5066
    5067    def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
    5068        this = self._parse_type()
    5069        if not this:
    5070            return None
    5071
    5072        if isinstance(this, exp.Column) and not this.table:
    5073            this = exp.var(this.name.upper())
    5074
    5075        return self.expression(
    5076            exp.DataTypeParam, this=this, expression=self._parse_var(any_token=True)
    5077        )
    5078
    5079    def _parse_types(
    5080        self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
    5081    ) -> t.Optional[exp.Expression]:
    5082        index = self._index
    5083
    5084        this: t.Optional[exp.Expression] = None
    5085        prefix = self._match_text_seq("SYSUDTLIB", ".")
    5086
    5087        if not self._match_set(self.TYPE_TOKENS):
    5088            identifier = allow_identifiers and self._parse_id_var(
    5089                any_token=False, tokens=(TokenType.VAR,)
    5090            )
    5091            if isinstance(identifier, exp.Identifier):
    5092                tokens = self.dialect.tokenize(identifier.sql(dialect=self.dialect))
    5093
    5094                if len(tokens) != 1:
    5095                    self.raise_error("Unexpected identifier", self._prev)
    5096
    5097                if tokens[0].token_type in self.TYPE_TOKENS:
    5098                    self._prev = tokens[0]
    5099                elif self.dialect.SUPPORTS_USER_DEFINED_TYPES:
    5100                    type_name = identifier.name
    5101
    5102                    while self._match(TokenType.DOT):
    5103                        type_name = f"{type_name}.{self._advance_any() and self._prev.text}"
    5104
    5105                    this = exp.DataType.build(type_name, udt=True)
    5106                else:
    5107                    self._retreat(self._index - 1)
    5108                    return None
    5109            else:
    5110                return None
    5111
    5112        type_token = self._prev.token_type
    5113
    5114        if type_token == TokenType.PSEUDO_TYPE:
    5115            return self.expression(exp.PseudoType, this=self._prev.text.upper())
    5116
    5117        if type_token == TokenType.OBJECT_IDENTIFIER:
    5118            return self.expression(exp.ObjectIdentifier, this=self._prev.text.upper())
    5119
    5120        # https://materialize.com/docs/sql/types/map/
    5121        if type_token == TokenType.MAP and self._match(TokenType.L_BRACKET):
    5122            key_type = self._parse_types(
    5123                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    5124            )
    5125            if not self._match(TokenType.FARROW):
    5126                self._retreat(index)
    5127                return None
    5128
    5129            value_type = self._parse_types(
    5130                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    5131            )
    5132            if not self._match(TokenType.R_BRACKET):
    5133                self._retreat(index)
    5134                return None
    5135
    5136            return exp.DataType(
    5137                this=exp.DataType.Type.MAP,
    5138                expressions=[key_type, value_type],
    5139                nested=True,
    5140                prefix=prefix,
    5141            )
    5142
    5143        nested = type_token in self.NESTED_TYPE_TOKENS
    5144        is_struct = type_token in self.STRUCT_TYPE_TOKENS
    5145        is_aggregate = type_token in self.AGGREGATE_TYPE_TOKENS
    5146        expressions = None
    5147        maybe_func = False
    5148
    5149        if self._match(TokenType.L_PAREN):
    5150            if is_struct:
    5151                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
    5152            elif nested:
    5153                expressions = self._parse_csv(
    5154                    lambda: self._parse_types(
    5155                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    5156                    )
    5157                )
    5158                if type_token == TokenType.NULLABLE and len(expressions) == 1:
    5159                    this = expressions[0]
    5160                    this.set("nullable", True)
    5161                    self._match_r_paren()
    5162                    return this
    5163            elif type_token in self.ENUM_TYPE_TOKENS:
    5164                expressions = self._parse_csv(self._parse_equality)
    5165            elif is_aggregate:
    5166                func_or_ident = self._parse_function(anonymous=True) or self._parse_id_var(
    5167                    any_token=False, tokens=(TokenType.VAR, TokenType.ANY)
    5168                )
    5169                if not func_or_ident:
    5170                    return None
    5171                expressions = [func_or_ident]
    5172                if self._match(TokenType.COMMA):
    5173                    expressions.extend(
    5174                        self._parse_csv(
    5175                            lambda: self._parse_types(
    5176                                check_func=check_func,
    5177                                schema=schema,
    5178                                allow_identifiers=allow_identifiers,
    5179                            )
    5180                        )
    5181                    )
    5182            else:
    5183                expressions = self._parse_csv(self._parse_type_size)
    5184
    5185                # https://docs.snowflake.com/en/sql-reference/data-types-vector
    5186                if type_token == TokenType.VECTOR and len(expressions) == 2:
    5187                    expressions[0] = exp.DataType.build(expressions[0].name, dialect=self.dialect)
    5188
    5189            if not expressions or not self._match(TokenType.R_PAREN):
    5190                self._retreat(index)
    5191                return None
    5192
    5193            maybe_func = True
    5194
    5195        values: t.Optional[t.List[exp.Expression]] = None
    5196
    5197        if nested and self._match(TokenType.LT):
    5198            if is_struct:
    5199                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
    5200            else:
    5201                expressions = self._parse_csv(
    5202                    lambda: self._parse_types(
    5203                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    5204                    )
    5205                )
    5206
    5207            if not self._match(TokenType.GT):
    5208                self.raise_error("Expecting >")
    5209
    5210            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
    5211                values = self._parse_csv(self._parse_assignment)
    5212                if not values and is_struct:
    5213                    values = None
    5214                    self._retreat(self._index - 1)
    5215                else:
    5216                    self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
    5217
    5218        if type_token in self.TIMESTAMPS:
    5219            if self._match_text_seq("WITH", "TIME", "ZONE"):
    5220                maybe_func = False
    5221                tz_type = (
    5222                    exp.DataType.Type.TIMETZ
    5223                    if type_token in self.TIMES
    5224                    else exp.DataType.Type.TIMESTAMPTZ
    5225                )
    5226                this = exp.DataType(this=tz_type, expressions=expressions)
    5227            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
    5228                maybe_func = False
    5229                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
    5230            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
    5231                maybe_func = False
    5232        elif type_token == TokenType.INTERVAL:
    5233            unit = self._parse_var(upper=True)
    5234            if unit:
    5235                if self._match_text_seq("TO"):
    5236                    unit = exp.IntervalSpan(this=unit, expression=self._parse_var(upper=True))
    5237
    5238                this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
    5239            else:
    5240                this = self.expression(exp.DataType, this=exp.DataType.Type.INTERVAL)
    5241
    5242        if maybe_func and check_func:
    5243            index2 = self._index
    5244            peek = self._parse_string()
    5245
    5246            if not peek:
    5247                self._retreat(index)
    5248                return None
    5249
    5250            self._retreat(index2)
    5251
    5252        if not this:
    5253            if self._match_text_seq("UNSIGNED"):
    5254                unsigned_type_token = self.SIGNED_TO_UNSIGNED_TYPE_TOKEN.get(type_token)
    5255                if not unsigned_type_token:
    5256                    self.raise_error(f"Cannot convert {type_token.value} to unsigned.")
    5257
    5258                type_token = unsigned_type_token or type_token
    5259
    5260            this = exp.DataType(
    5261                this=exp.DataType.Type[type_token.value],
    5262                expressions=expressions,
    5263                nested=nested,
    5264                prefix=prefix,
    5265            )
    5266
    5267            # Empty arrays/structs are allowed
    5268            if values is not None:
    5269                cls = exp.Struct if is_struct else exp.Array
    5270                this = exp.cast(cls(expressions=values), this, copy=False)
    5271
    5272        elif expressions:
    5273            this.set("expressions", expressions)
    5274
    5275        # https://materialize.com/docs/sql/types/list/#type-name
    5276        while self._match(TokenType.LIST):
    5277            this = exp.DataType(this=exp.DataType.Type.LIST, expressions=[this], nested=True)
    5278
    5279        index = self._index
    5280
    5281        # Postgres supports the INT ARRAY[3] syntax as a synonym for INT[3]
    5282        matched_array = self._match(TokenType.ARRAY)
    5283
    5284        while self._curr:
    5285            datatype_token = self._prev.token_type
    5286            matched_l_bracket = self._match(TokenType.L_BRACKET)
    5287
    5288            if (not matched_l_bracket and not matched_array) or (
    5289                datatype_token == TokenType.ARRAY and self._match(TokenType.R_BRACKET)
    5290            ):
    5291                # Postgres allows casting empty arrays such as ARRAY[]::INT[],
    5292                # not to be confused with the fixed size array parsing
    5293                break
    5294
    5295            matched_array = False
    5296            values = self._parse_csv(self._parse_assignment) or None
    5297            if (
    5298                values
    5299                and not schema
    5300                and (
    5301                    not self.dialect.SUPPORTS_FIXED_SIZE_ARRAYS or datatype_token == TokenType.ARRAY
    5302                )
    5303            ):
    5304                # Retreating here means that we should not parse the following values as part of the data type, e.g. in DuckDB
    5305                # ARRAY[1] should retreat and instead be parsed into exp.Array in contrast to INT[x][y] which denotes a fixed-size array data type
    5306                self._retreat(index)
    5307                break
    5308
    5309            this = exp.DataType(
    5310                this=exp.DataType.Type.ARRAY, expressions=[this], values=values, nested=True
    5311            )
    5312            self._match(TokenType.R_BRACKET)
    5313
    5314        if self.TYPE_CONVERTERS and isinstance(this.this, exp.DataType.Type):
    5315            converter = self.TYPE_CONVERTERS.get(this.this)
    5316            if converter:
    5317                this = converter(t.cast(exp.DataType, this))
    5318
    5319        return this
    5320
    5321    def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
    5322        index = self._index
    5323
    5324        if (
    5325            self._curr
    5326            and self._next
    5327            and self._curr.token_type in self.TYPE_TOKENS
    5328            and self._next.token_type in self.TYPE_TOKENS
    5329        ):
    5330            # Takes care of special cases like `STRUCT<list ARRAY<...>>` where the identifier is also a
    5331            # type token. Without this, the list will be parsed as a type and we'll eventually crash
    5332            this = self._parse_id_var()
    5333        else:
    5334            this = (
    5335                self._parse_type(parse_interval=False, fallback_to_identifier=True)
    5336                or self._parse_id_var()
    5337            )
    5338
    5339        self._match(TokenType.COLON)
    5340
    5341        if (
    5342            type_required
    5343            and not isinstance(this, exp.DataType)
    5344            and not self._match_set(self.TYPE_TOKENS, advance=False)
    5345        ):
    5346            self._retreat(index)
    5347            return self._parse_types()
    5348
    5349        return self._parse_column_def(this)
    5350
    5351    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    5352        if not self._match_text_seq("AT", "TIME", "ZONE"):
    5353            return this
    5354        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
    5355
    5356    def _parse_column(self) -> t.Optional[exp.Expression]:
    5357        this = self._parse_column_reference()
    5358        column = self._parse_column_ops(this) if this else self._parse_bracket(this)
    5359
    5360        if self.dialect.SUPPORTS_COLUMN_JOIN_MARKS and column:
    5361            column.set("join_mark", self._match(TokenType.JOIN_MARKER))
    5362
    5363        return column
    5364
    5365    def _parse_column_reference(self) -> t.Optional[exp.Expression]:
    5366        this = self._parse_field()
    5367        if (
    5368            not this
    5369            and self._match(TokenType.VALUES, advance=False)
    5370            and self.VALUES_FOLLOWED_BY_PAREN
    5371            and (not self._next or self._next.token_type != TokenType.L_PAREN)
    5372        ):
    5373            this = self._parse_id_var()
    5374
    5375        if isinstance(this, exp.Identifier):
    5376            # We bubble up comments from the Identifier to the Column
    5377            this = self.expression(exp.Column, comments=this.pop_comments(), this=this)
    5378
    5379        return this
    5380
    5381    def _parse_colon_as_variant_extract(
    5382        self, this: t.Optional[exp.Expression]
    5383    ) -> t.Optional[exp.Expression]:
    5384        casts = []
    5385        json_path = []
    5386        escape = None
    5387
    5388        while self._match(TokenType.COLON):
    5389            start_index = self._index
    5390
    5391            # Snowflake allows reserved keywords as json keys but advance_any() excludes TokenType.SELECT from any_tokens=True
    5392            path = self._parse_column_ops(
    5393                self._parse_field(any_token=True, tokens=(TokenType.SELECT,))
    5394            )
    5395
    5396            # The cast :: operator has a lower precedence than the extraction operator :, so
    5397            # we rearrange the AST appropriately to avoid casting the JSON path
    5398            while isinstance(path, exp.Cast):
    5399                casts.append(path.to)
    5400                path = path.this
    5401
    5402            if casts:
    5403                dcolon_offset = next(
    5404                    i
    5405                    for i, t in enumerate(self._tokens[start_index:])
    5406                    if t.token_type == TokenType.DCOLON
    5407                )
    5408                end_token = self._tokens[start_index + dcolon_offset - 1]
    5409            else:
    5410                end_token = self._prev
    5411
    5412            if path:
    5413                # Escape single quotes from Snowflake's colon extraction (e.g. col:"a'b") as
    5414                # it'll roundtrip to a string literal in GET_PATH
    5415                if isinstance(path, exp.Identifier) and path.quoted:
    5416                    escape = True
    5417
    5418                json_path.append(self._find_sql(self._tokens[start_index], end_token))
    5419
    5420        # The VARIANT extract in Snowflake/Databricks is parsed as a JSONExtract; Snowflake uses the json_path in GET_PATH() while
    5421        # Databricks transforms it back to the colon/dot notation
    5422        if json_path:
    5423            json_path_expr = self.dialect.to_json_path(exp.Literal.string(".".join(json_path)))
    5424
    5425            if json_path_expr:
    5426                json_path_expr.set("escape", escape)
    5427
    5428            this = self.expression(
    5429                exp.JSONExtract,
    5430                this=this,
    5431                expression=json_path_expr,
    5432                variant_extract=True,
    5433            )
    5434
    5435            while casts:
    5436                this = self.expression(exp.Cast, this=this, to=casts.pop())
    5437
    5438        return this
    5439
    5440    def _parse_dcolon(self) -> t.Optional[exp.Expression]:
    5441        return self._parse_types()
    5442
    5443    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    5444        this = self._parse_bracket(this)
    5445
    5446        while self._match_set(self.COLUMN_OPERATORS):
    5447            op_token = self._prev.token_type
    5448            op = self.COLUMN_OPERATORS.get(op_token)
    5449
    5450            if op_token in (TokenType.DCOLON, TokenType.DOTCOLON):
    5451                field = self._parse_dcolon()
    5452                if not field:
    5453                    self.raise_error("Expected type")
    5454            elif op and self._curr:
    5455                field = self._parse_column_reference() or self._parse_bracket()
    5456                if isinstance(field, exp.Column) and self._match(TokenType.DOT, advance=False):
    5457                    field = self._parse_column_ops(field)
    5458            else:
    5459                field = self._parse_field(any_token=True, anonymous_func=True)
    5460
    5461            if isinstance(field, (exp.Func, exp.Window)) and this:
    5462                # BQ & snowflake allow function calls like x.y.count(...), SAFE.SUBSTR(...) etc
    5463                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
    5464                this = exp.replace_tree(
    5465                    this,
    5466                    lambda n: (
    5467                        self.expression(exp.Dot, this=n.args.get("table"), expression=n.this)
    5468                        if n.table
    5469                        else n.this
    5470                    )
    5471                    if isinstance(n, exp.Column)
    5472                    else n,
    5473                )
    5474
    5475            if op:
    5476                this = op(self, this, field)
    5477            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
    5478                this = self.expression(
    5479                    exp.Column,
    5480                    comments=this.comments,
    5481                    this=field,
    5482                    table=this.this,
    5483                    db=this.args.get("table"),
    5484                    catalog=this.args.get("db"),
    5485                )
    5486            elif isinstance(field, exp.Window):
    5487                # Move the exp.Dot's to the window's function
    5488                window_func = self.expression(exp.Dot, this=this, expression=field.this)
    5489                field.set("this", window_func)
    5490                this = field
    5491            else:
    5492                this = self.expression(exp.Dot, this=this, expression=field)
    5493
    5494            if field and field.comments:
    5495                t.cast(exp.Expression, this).add_comments(field.pop_comments())
    5496
    5497            this = self._parse_bracket(this)
    5498
    5499        return self._parse_colon_as_variant_extract(this) if self.COLON_IS_VARIANT_EXTRACT else this
    5500
    5501    def _parse_primary(self) -> t.Optional[exp.Expression]:
    5502        if self._match_set(self.PRIMARY_PARSERS):
    5503            token_type = self._prev.token_type
    5504            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
    5505
    5506            if token_type == TokenType.STRING:
    5507                expressions = [primary]
    5508                while self._match(TokenType.STRING):
    5509                    expressions.append(exp.Literal.string(self._prev.text))
    5510
    5511                if len(expressions) > 1:
    5512                    return self.expression(exp.Concat, expressions=expressions)
    5513
    5514            return primary
    5515
    5516        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
    5517            return exp.Literal.number(f"0.{self._prev.text}")
    5518
    5519        if self._match(TokenType.L_PAREN):
    5520            comments = self._prev_comments
    5521            query = self._parse_select()
    5522
    5523            if query:
    5524                expressions = [query]
    5525            else:
    5526                expressions = self._parse_expressions()
    5527
    5528            this = self._parse_query_modifiers(seq_get(expressions, 0))
    5529
    5530            if not this and self._match(TokenType.R_PAREN, advance=False):
    5531                this = self.expression(exp.Tuple)
    5532            elif isinstance(this, exp.UNWRAPPED_QUERIES):
    5533                this = self._parse_subquery(this=this, parse_alias=False)
    5534            elif isinstance(this, exp.Subquery):
    5535                this = self._parse_subquery(
    5536                    this=self._parse_set_operations(this), parse_alias=False
    5537                )
    5538            elif len(expressions) > 1 or self._prev.token_type == TokenType.COMMA:
    5539                this = self.expression(exp.Tuple, expressions=expressions)
    5540            else:
    5541                this = self.expression(exp.Paren, this=this)
    5542
    5543            if this:
    5544                this.add_comments(comments)
    5545
    5546            self._match_r_paren(expression=this)
    5547            return this
    5548
    5549        return None
    5550
    5551    def _parse_field(
    5552        self,
    5553        any_token: bool = False,
    5554        tokens: t.Optional[t.Collection[TokenType]] = None,
    5555        anonymous_func: bool = False,
    5556    ) -> t.Optional[exp.Expression]:
    5557        if anonymous_func:
    5558            field = (
    5559                self._parse_function(anonymous=anonymous_func, any_token=any_token)
    5560                or self._parse_primary()
    5561            )
    5562        else:
    5563            field = self._parse_primary() or self._parse_function(
    5564                anonymous=anonymous_func, any_token=any_token
    5565            )
    5566        return field or self._parse_id_var(any_token=any_token, tokens=tokens)
    5567
    5568    def _parse_function(
    5569        self,
    5570        functions: t.Optional[t.Dict[str, t.Callable]] = None,
    5571        anonymous: bool = False,
    5572        optional_parens: bool = True,
    5573        any_token: bool = False,
    5574    ) -> t.Optional[exp.Expression]:
    5575        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
    5576        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
    5577        fn_syntax = False
    5578        if (
    5579            self._match(TokenType.L_BRACE, advance=False)
    5580            and self._next
    5581            and self._next.text.upper() == "FN"
    5582        ):
    5583            self._advance(2)
    5584            fn_syntax = True
    5585
    5586        func = self._parse_function_call(
    5587            functions=functions,
    5588            anonymous=anonymous,
    5589            optional_parens=optional_parens,
    5590            any_token=any_token,
    5591        )
    5592
    5593        if fn_syntax:
    5594            self._match(TokenType.R_BRACE)
    5595
    5596        return func
    5597
    5598    def _parse_function_call(
    5599        self,
    5600        functions: t.Optional[t.Dict[str, t.Callable]] = None,
    5601        anonymous: bool = False,
    5602        optional_parens: bool = True,
    5603        any_token: bool = False,
    5604    ) -> t.Optional[exp.Expression]:
    5605        if not self._curr:
    5606            return None
    5607
    5608        comments = self._curr.comments
    5609        token_type = self._curr.token_type
    5610        this = self._curr.text
    5611        upper = this.upper()
    5612
    5613        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
    5614        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
    5615            self._advance()
    5616            return self._parse_window(parser(self))
    5617
    5618        if not self._next or self._next.token_type != TokenType.L_PAREN:
    5619            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
    5620                self._advance()
    5621                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
    5622
    5623            return None
    5624
    5625        if any_token:
    5626            if token_type in self.RESERVED_TOKENS:
    5627                return None
    5628        elif token_type not in self.FUNC_TOKENS:
    5629            return None
    5630
    5631        self._advance(2)
    5632
    5633        parser = self.FUNCTION_PARSERS.get(upper)
    5634        if parser and not anonymous:
    5635            this = parser(self)
    5636        else:
    5637            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
    5638
    5639            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
    5640                this = self.expression(
    5641                    subquery_predicate, comments=comments, this=self._parse_select()
    5642                )
    5643                self._match_r_paren()
    5644                return this
    5645
    5646            if functions is None:
    5647                functions = self.FUNCTIONS
    5648
    5649            function = functions.get(upper)
    5650            known_function = function and not anonymous
    5651
    5652            alias = not known_function or upper in self.FUNCTIONS_WITH_ALIASED_ARGS
    5653            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
    5654
    5655            post_func_comments = self._curr and self._curr.comments
    5656            if known_function and post_func_comments:
    5657                # If the user-inputted comment "/* sqlglot.anonymous */" is following the function
    5658                # call we'll construct it as exp.Anonymous, even if it's "known"
    5659                if any(
    5660                    comment.lstrip().startswith(exp.SQLGLOT_ANONYMOUS)
    5661                    for comment in post_func_comments
    5662                ):
    5663                    known_function = False
    5664
    5665            if alias and known_function:
    5666                args = self._kv_to_prop_eq(args)
    5667
    5668            if known_function:
    5669                func_builder = t.cast(t.Callable, function)
    5670
    5671                if "dialect" in func_builder.__code__.co_varnames:
    5672                    func = func_builder(args, dialect=self.dialect)
    5673                else:
    5674                    func = func_builder(args)
    5675
    5676                func = self.validate_expression(func, args)
    5677                if self.dialect.PRESERVE_ORIGINAL_NAMES:
    5678                    func.meta["name"] = this
    5679
    5680                this = func
    5681            else:
    5682                if token_type == TokenType.IDENTIFIER:
    5683                    this = exp.Identifier(this=this, quoted=True)
    5684                this = self.expression(exp.Anonymous, this=this, expressions=args)
    5685
    5686        if isinstance(this, exp.Expression):
    5687            this.add_comments(comments)
    5688
    5689        self._match_r_paren(this)
    5690        return self._parse_window(this)
    5691
    5692    def _to_prop_eq(self, expression: exp.Expression, index: int) -> exp.Expression:
    5693        return expression
    5694
    5695    def _kv_to_prop_eq(self, expressions: t.List[exp.Expression]) -> t.List[exp.Expression]:
    5696        transformed = []
    5697
    5698        for index, e in enumerate(expressions):
    5699            if isinstance(e, self.KEY_VALUE_DEFINITIONS):
    5700                if isinstance(e, exp.Alias):
    5701                    e = self.expression(exp.PropertyEQ, this=e.args.get("alias"), expression=e.this)
    5702
    5703                if not isinstance(e, exp.PropertyEQ):
    5704                    e = self.expression(
    5705                        exp.PropertyEQ, this=exp.to_identifier(e.this.name), expression=e.expression
    5706                    )
    5707
    5708                if isinstance(e.this, exp.Column):
    5709                    e.this.replace(e.this.this)
    5710            else:
    5711                e = self._to_prop_eq(e, index)
    5712
    5713            transformed.append(e)
    5714
    5715        return transformed
    5716
    5717    def _parse_user_defined_function_expression(self) -> t.Optional[exp.Expression]:
    5718        return self._parse_statement()
    5719
    5720    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
    5721        return self._parse_column_def(this=self._parse_id_var(), computed_column=False)
    5722
    5723    def _parse_user_defined_function(
    5724        self, kind: t.Optional[TokenType] = None
    5725    ) -> t.Optional[exp.Expression]:
    5726        this = self._parse_table_parts(schema=True)
    5727
    5728        if not self._match(TokenType.L_PAREN):
    5729            return this
    5730
    5731        expressions = self._parse_csv(self._parse_function_parameter)
    5732        self._match_r_paren()
    5733        return self.expression(
    5734            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
    5735        )
    5736
    5737    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
    5738        literal = self._parse_primary()
    5739        if literal:
    5740            return self.expression(exp.Introducer, this=token.text, expression=literal)
    5741
    5742        return self.expression(exp.Identifier, this=token.text)
    5743
    5744    def _parse_session_parameter(self) -> exp.SessionParameter:
    5745        kind = None
    5746        this = self._parse_id_var() or self._parse_primary()
    5747
    5748        if this and self._match(TokenType.DOT):
    5749            kind = this.name
    5750            this = self._parse_var() or self._parse_primary()
    5751
    5752        return self.expression(exp.SessionParameter, this=this, kind=kind)
    5753
    5754    def _parse_lambda_arg(self) -> t.Optional[exp.Expression]:
    5755        return self._parse_id_var()
    5756
    5757    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
    5758        index = self._index
    5759
    5760        if self._match(TokenType.L_PAREN):
    5761            expressions = t.cast(
    5762                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_lambda_arg)
    5763            )
    5764
    5765            if not self._match(TokenType.R_PAREN):
    5766                self._retreat(index)
    5767        else:
    5768            expressions = [self._parse_lambda_arg()]
    5769
    5770        if self._match_set(self.LAMBDAS):
    5771            return self.LAMBDAS[self._prev.token_type](self, expressions)
    5772
    5773        self._retreat(index)
    5774
    5775        this: t.Optional[exp.Expression]
    5776
    5777        if self._match(TokenType.DISTINCT):
    5778            this = self.expression(
    5779                exp.Distinct, expressions=self._parse_csv(self._parse_assignment)
    5780            )
    5781        else:
    5782            this = self._parse_select_or_expression(alias=alias)
    5783
    5784        return self._parse_limit(
    5785            self._parse_order(self._parse_having_max(self._parse_respect_or_ignore_nulls(this)))
    5786        )
    5787
    5788    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    5789        index = self._index
    5790        if not self._match(TokenType.L_PAREN):
    5791            return this
    5792
    5793        # Disambiguate between schema and subquery/CTE, e.g. in INSERT INTO table (<expr>),
    5794        # expr can be of both types
    5795        if self._match_set(self.SELECT_START_TOKENS):
    5796            self._retreat(index)
    5797            return this
    5798        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
    5799        self._match_r_paren()
    5800        return self.expression(exp.Schema, this=this, expressions=args)
    5801
    5802    def _parse_field_def(self) -> t.Optional[exp.Expression]:
    5803        return self._parse_column_def(self._parse_field(any_token=True))
    5804
    5805    def _parse_column_def(
    5806        self, this: t.Optional[exp.Expression], computed_column: bool = True
    5807    ) -> t.Optional[exp.Expression]:
    5808        # column defs are not really columns, they're identifiers
    5809        if isinstance(this, exp.Column):
    5810            this = this.this
    5811
    5812        if not computed_column:
    5813            self._match(TokenType.ALIAS)
    5814
    5815        kind = self._parse_types(schema=True)
    5816
    5817        if self._match_text_seq("FOR", "ORDINALITY"):
    5818            return self.expression(exp.ColumnDef, this=this, ordinality=True)
    5819
    5820        constraints: t.List[exp.Expression] = []
    5821
    5822        if (not kind and self._match(TokenType.ALIAS)) or self._match_texts(
    5823            ("ALIAS", "MATERIALIZED")
    5824        ):
    5825            persisted = self._prev.text.upper() == "MATERIALIZED"
    5826            constraint_kind = exp.ComputedColumnConstraint(
    5827                this=self._parse_assignment(),
    5828                persisted=persisted or self._match_text_seq("PERSISTED"),
    5829                not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
    5830            )
    5831            constraints.append(self.expression(exp.ColumnConstraint, kind=constraint_kind))
    5832        elif (
    5833            kind
    5834            and self._match(TokenType.ALIAS, advance=False)
    5835            and (
    5836                not self.WRAPPED_TRANSFORM_COLUMN_CONSTRAINT
    5837                or (self._next and self._next.token_type == TokenType.L_PAREN)
    5838            )
    5839        ):
    5840            self._advance()
    5841            constraints.append(
    5842                self.expression(
    5843                    exp.ColumnConstraint,
    5844                    kind=exp.TransformColumnConstraint(this=self._parse_disjunction()),
    5845                )
    5846            )
    5847
    5848        while True:
    5849            constraint = self._parse_column_constraint()
    5850            if not constraint:
    5851                break
    5852            constraints.append(constraint)
    5853
    5854        if not kind and not constraints:
    5855            return this
    5856
    5857        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
    5858
    5859    def _parse_auto_increment(
    5860        self,
    5861    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
    5862        start = None
    5863        increment = None
    5864
    5865        if self._match(TokenType.L_PAREN, advance=False):
    5866            args = self._parse_wrapped_csv(self._parse_bitwise)
    5867            start = seq_get(args, 0)
    5868            increment = seq_get(args, 1)
    5869        elif self._match_text_seq("START"):
    5870            start = self._parse_bitwise()
    5871            self._match_text_seq("INCREMENT")
    5872            increment = self._parse_bitwise()
    5873
    5874        if start and increment:
    5875            return exp.GeneratedAsIdentityColumnConstraint(
    5876                start=start, increment=increment, this=False
    5877            )
    5878
    5879        return exp.AutoIncrementColumnConstraint()
    5880
    5881    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
    5882        if not self._match_text_seq("REFRESH"):
    5883            self._retreat(self._index - 1)
    5884            return None
    5885        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
    5886
    5887    def _parse_compress(self) -> exp.CompressColumnConstraint:
    5888        if self._match(TokenType.L_PAREN, advance=False):
    5889            return self.expression(
    5890                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
    5891            )
    5892
    5893        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
    5894
    5895    def _parse_generated_as_identity(
    5896        self,
    5897    ) -> (
    5898        exp.GeneratedAsIdentityColumnConstraint
    5899        | exp.ComputedColumnConstraint
    5900        | exp.GeneratedAsRowColumnConstraint
    5901    ):
    5902        if self._match_text_seq("BY", "DEFAULT"):
    5903            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
    5904            this = self.expression(
    5905                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
    5906            )
    5907        else:
    5908            self._match_text_seq("ALWAYS")
    5909            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
    5910
    5911        self._match(TokenType.ALIAS)
    5912
    5913        if self._match_text_seq("ROW"):
    5914            start = self._match_text_seq("START")
    5915            if not start:
    5916                self._match(TokenType.END)
    5917            hidden = self._match_text_seq("HIDDEN")
    5918            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
    5919
    5920        identity = self._match_text_seq("IDENTITY")
    5921
    5922        if self._match(TokenType.L_PAREN):
    5923            if self._match(TokenType.START_WITH):
    5924                this.set("start", self._parse_bitwise())
    5925            if self._match_text_seq("INCREMENT", "BY"):
    5926                this.set("increment", self._parse_bitwise())
    5927            if self._match_text_seq("MINVALUE"):
    5928                this.set("minvalue", self._parse_bitwise())
    5929            if self._match_text_seq("MAXVALUE"):
    5930                this.set("maxvalue", self._parse_bitwise())
    5931
    5932            if self._match_text_seq("CYCLE"):
    5933                this.set("cycle", True)
    5934            elif self._match_text_seq("NO", "CYCLE"):
    5935                this.set("cycle", False)
    5936
    5937            if not identity:
    5938                this.set("expression", self._parse_range())
    5939            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
    5940                args = self._parse_csv(self._parse_bitwise)
    5941                this.set("start", seq_get(args, 0))
    5942                this.set("increment", seq_get(args, 1))
    5943
    5944            self._match_r_paren()
    5945
    5946        return this
    5947
    5948    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
    5949        self._match_text_seq("LENGTH")
    5950        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
    5951
    5952    def _parse_not_constraint(self) -> t.Optional[exp.Expression]:
    5953        if self._match_text_seq("NULL"):
    5954            return self.expression(exp.NotNullColumnConstraint)
    5955        if self._match_text_seq("CASESPECIFIC"):
    5956            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
    5957        if self._match_text_seq("FOR", "REPLICATION"):
    5958            return self.expression(exp.NotForReplicationColumnConstraint)
    5959
    5960        # Unconsume the `NOT` token
    5961        self._retreat(self._index - 1)
    5962        return None
    5963
    5964    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
    5965        this = self._match(TokenType.CONSTRAINT) and self._parse_id_var()
    5966
    5967        procedure_option_follows = (
    5968            self._match(TokenType.WITH, advance=False)
    5969            and self._next
    5970            and self._next.text.upper() in self.PROCEDURE_OPTIONS
    5971        )
    5972
    5973        if not procedure_option_follows and self._match_texts(self.CONSTRAINT_PARSERS):
    5974            return self.expression(
    5975                exp.ColumnConstraint,
    5976                this=this,
    5977                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
    5978            )
    5979
    5980        return this
    5981
    5982    def _parse_constraint(self) -> t.Optional[exp.Expression]:
    5983        if not self._match(TokenType.CONSTRAINT):
    5984            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
    5985
    5986        return self.expression(
    5987            exp.Constraint,
    5988            this=self._parse_id_var(),
    5989            expressions=self._parse_unnamed_constraints(),
    5990        )
    5991
    5992    def _parse_unnamed_constraints(self) -> t.List[exp.Expression]:
    5993        constraints = []
    5994        while True:
    5995            constraint = self._parse_unnamed_constraint() or self._parse_function()
    5996            if not constraint:
    5997                break
    5998            constraints.append(constraint)
    5999
    6000        return constraints
    6001
    6002    def _parse_unnamed_constraint(
    6003        self, constraints: t.Optional[t.Collection[str]] = None
    6004    ) -> t.Optional[exp.Expression]:
    6005        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
    6006            constraints or self.CONSTRAINT_PARSERS
    6007        ):
    6008            return None
    6009
    6010        constraint = self._prev.text.upper()
    6011        if constraint not in self.CONSTRAINT_PARSERS:
    6012            self.raise_error(f"No parser found for schema constraint {constraint}.")
    6013
    6014        return self.CONSTRAINT_PARSERS[constraint](self)
    6015
    6016    def _parse_unique_key(self) -> t.Optional[exp.Expression]:
    6017        return self._parse_id_var(any_token=False)
    6018
    6019    def _parse_unique(self) -> exp.UniqueColumnConstraint:
    6020        self._match_text_seq("KEY")
    6021        return self.expression(
    6022            exp.UniqueColumnConstraint,
    6023            nulls=self._match_text_seq("NULLS", "NOT", "DISTINCT"),
    6024            this=self._parse_schema(self._parse_unique_key()),
    6025            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
    6026            on_conflict=self._parse_on_conflict(),
    6027            options=self._parse_key_constraint_options(),
    6028        )
    6029
    6030    def _parse_key_constraint_options(self) -> t.List[str]:
    6031        options = []
    6032        while True:
    6033            if not self._curr:
    6034                break
    6035
    6036            if self._match(TokenType.ON):
    6037                action = None
    6038                on = self._advance_any() and self._prev.text
    6039
    6040                if self._match_text_seq("NO", "ACTION"):
    6041                    action = "NO ACTION"
    6042                elif self._match_text_seq("CASCADE"):
    6043                    action = "CASCADE"
    6044                elif self._match_text_seq("RESTRICT"):
    6045                    action = "RESTRICT"
    6046                elif self._match_pair(TokenType.SET, TokenType.NULL):
    6047                    action = "SET NULL"
    6048                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
    6049                    action = "SET DEFAULT"
    6050                else:
    6051                    self.raise_error("Invalid key constraint")
    6052
    6053                options.append(f"ON {on} {action}")
    6054            else:
    6055                var = self._parse_var_from_options(
    6056                    self.KEY_CONSTRAINT_OPTIONS, raise_unmatched=False
    6057                )
    6058                if not var:
    6059                    break
    6060                options.append(var.name)
    6061
    6062        return options
    6063
    6064    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
    6065        if match and not self._match(TokenType.REFERENCES):
    6066            return None
    6067
    6068        expressions = None
    6069        this = self._parse_table(schema=True)
    6070        options = self._parse_key_constraint_options()
    6071        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
    6072
    6073    def _parse_foreign_key(self) -> exp.ForeignKey:
    6074        expressions = self._parse_wrapped_id_vars()
    6075        reference = self._parse_references()
    6076        on_options = {}
    6077
    6078        while self._match(TokenType.ON):
    6079            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
    6080                self.raise_error("Expected DELETE or UPDATE")
    6081
    6082            kind = self._prev.text.lower()
    6083
    6084            if self._match_text_seq("NO", "ACTION"):
    6085                action = "NO ACTION"
    6086            elif self._match(TokenType.SET):
    6087                self._match_set((TokenType.NULL, TokenType.DEFAULT))
    6088                action = "SET " + self._prev.text.upper()
    6089            else:
    6090                self._advance()
    6091                action = self._prev.text.upper()
    6092
    6093            on_options[kind] = action
    6094
    6095        return self.expression(
    6096            exp.ForeignKey,
    6097            expressions=expressions,
    6098            reference=reference,
    6099            options=self._parse_key_constraint_options(),
    6100            **on_options,  # type: ignore
    6101        )
    6102
    6103    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
    6104        return self._parse_ordered() or self._parse_field()
    6105
    6106    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
    6107        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
    6108            self._retreat(self._index - 1)
    6109            return None
    6110
    6111        id_vars = self._parse_wrapped_id_vars()
    6112        return self.expression(
    6113            exp.PeriodForSystemTimeConstraint,
    6114            this=seq_get(id_vars, 0),
    6115            expression=seq_get(id_vars, 1),
    6116        )
    6117
    6118    def _parse_primary_key(
    6119        self, wrapped_optional: bool = False, in_props: bool = False
    6120    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
    6121        desc = (
    6122            self._match_set((TokenType.ASC, TokenType.DESC))
    6123            and self._prev.token_type == TokenType.DESC
    6124        )
    6125
    6126        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
    6127            return self.expression(
    6128                exp.PrimaryKeyColumnConstraint,
    6129                desc=desc,
    6130                options=self._parse_key_constraint_options(),
    6131            )
    6132
    6133        expressions = self._parse_wrapped_csv(
    6134            self._parse_primary_key_part, optional=wrapped_optional
    6135        )
    6136        options = self._parse_key_constraint_options()
    6137        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
    6138
    6139    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
    6140        return self._parse_slice(self._parse_alias(self._parse_assignment(), explicit=True))
    6141
    6142    def _parse_odbc_datetime_literal(self) -> exp.Expression:
    6143        """
    6144        Parses a datetime column in ODBC format. We parse the column into the corresponding
    6145        types, for example `{d'yyyy-mm-dd'}` will be parsed as a `Date` column, exactly the
    6146        same as we did for `DATE('yyyy-mm-dd')`.
    6147
    6148        Reference:
    6149        https://learn.microsoft.com/en-us/sql/odbc/reference/develop-app/date-time-and-timestamp-literals
    6150        """
    6151        self._match(TokenType.VAR)
    6152        exp_class = self.ODBC_DATETIME_LITERALS[self._prev.text.lower()]
    6153        expression = self.expression(exp_class=exp_class, this=self._parse_string())
    6154        if not self._match(TokenType.R_BRACE):
    6155            self.raise_error("Expected }")
    6156        return expression
    6157
    6158    def _parse_bracket(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    6159        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
    6160            return this
    6161
    6162        bracket_kind = self._prev.token_type
    6163        if (
    6164            bracket_kind == TokenType.L_BRACE
    6165            and self._curr
    6166            and self._curr.token_type == TokenType.VAR
    6167            and self._curr.text.lower() in self.ODBC_DATETIME_LITERALS
    6168        ):
    6169            return self._parse_odbc_datetime_literal()
    6170
    6171        expressions = self._parse_csv(
    6172            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
    6173        )
    6174
    6175        if bracket_kind == TokenType.L_BRACKET and not self._match(TokenType.R_BRACKET):
    6176            self.raise_error("Expected ]")
    6177        elif bracket_kind == TokenType.L_BRACE and not self._match(TokenType.R_BRACE):
    6178            self.raise_error("Expected }")
    6179
    6180        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
    6181        if bracket_kind == TokenType.L_BRACE:
    6182            this = self.expression(exp.Struct, expressions=self._kv_to_prop_eq(expressions))
    6183        elif not this:
    6184            this = build_array_constructor(
    6185                exp.Array, args=expressions, bracket_kind=bracket_kind, dialect=self.dialect
    6186            )
    6187        else:
    6188            constructor_type = self.ARRAY_CONSTRUCTORS.get(this.name.upper())
    6189            if constructor_type:
    6190                return build_array_constructor(
    6191                    constructor_type,
    6192                    args=expressions,
    6193                    bracket_kind=bracket_kind,
    6194                    dialect=self.dialect,
    6195                )
    6196
    6197            expressions = apply_index_offset(
    6198                this, expressions, -self.dialect.INDEX_OFFSET, dialect=self.dialect
    6199            )
    6200            this = self.expression(exp.Bracket, this=this, expressions=expressions)
    6201
    6202        self._add_comments(this)
    6203        return self._parse_bracket(this)
    6204
    6205    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    6206        if self._match(TokenType.COLON):
    6207            return self.expression(exp.Slice, this=this, expression=self._parse_assignment())
    6208        return this
    6209
    6210    def _parse_case(self) -> t.Optional[exp.Expression]:
    6211        ifs = []
    6212        default = None
    6213
    6214        comments = self._prev_comments
    6215        expression = self._parse_assignment()
    6216
    6217        while self._match(TokenType.WHEN):
    6218            this = self._parse_assignment()
    6219            self._match(TokenType.THEN)
    6220            then = self._parse_assignment()
    6221            ifs.append(self.expression(exp.If, this=this, true=then))
    6222
    6223        if self._match(TokenType.ELSE):
    6224            default = self._parse_assignment()
    6225
    6226        if not self._match(TokenType.END):
    6227            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
    6228                default = exp.column("interval")
    6229            else:
    6230                self.raise_error("Expected END after CASE", self._prev)
    6231
    6232        return self.expression(
    6233            exp.Case, comments=comments, this=expression, ifs=ifs, default=default
    6234        )
    6235
    6236    def _parse_if(self) -> t.Optional[exp.Expression]:
    6237        if self._match(TokenType.L_PAREN):
    6238            args = self._parse_csv(
    6239                lambda: self._parse_alias(self._parse_assignment(), explicit=True)
    6240            )
    6241            this = self.validate_expression(exp.If.from_arg_list(args), args)
    6242            self._match_r_paren()
    6243        else:
    6244            index = self._index - 1
    6245
    6246            if self.NO_PAREN_IF_COMMANDS and index == 0:
    6247                return self._parse_as_command(self._prev)
    6248
    6249            condition = self._parse_assignment()
    6250
    6251            if not condition:
    6252                self._retreat(index)
    6253                return None
    6254
    6255            self._match(TokenType.THEN)
    6256            true = self._parse_assignment()
    6257            false = self._parse_assignment() if self._match(TokenType.ELSE) else None
    6258            self._match(TokenType.END)
    6259            this = self.expression(exp.If, this=condition, true=true, false=false)
    6260
    6261        return this
    6262
    6263    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
    6264        if not self._match_text_seq("VALUE", "FOR"):
    6265            self._retreat(self._index - 1)
    6266            return None
    6267
    6268        return self.expression(
    6269            exp.NextValueFor,
    6270            this=self._parse_column(),
    6271            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
    6272        )
    6273
    6274    def _parse_extract(self) -> exp.Extract | exp.Anonymous:
    6275        this = self._parse_function() or self._parse_var_or_string(upper=True)
    6276
    6277        if self._match(TokenType.FROM):
    6278            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
    6279
    6280        if not self._match(TokenType.COMMA):
    6281            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
    6282
    6283        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
    6284
    6285    def _parse_gap_fill(self) -> exp.GapFill:
    6286        self._match(TokenType.TABLE)
    6287        this = self._parse_table()
    6288
    6289        self._match(TokenType.COMMA)
    6290        args = [this, *self._parse_csv(self._parse_lambda)]
    6291
    6292        gap_fill = exp.GapFill.from_arg_list(args)
    6293        return self.validate_expression(gap_fill, args)
    6294
    6295    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
    6296        this = self._parse_assignment()
    6297
    6298        if not self._match(TokenType.ALIAS):
    6299            if self._match(TokenType.COMMA):
    6300                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
    6301
    6302            self.raise_error("Expected AS after CAST")
    6303
    6304        fmt = None
    6305        to = self._parse_types()
    6306
    6307        default = self._match(TokenType.DEFAULT)
    6308        if default:
    6309            default = self._parse_bitwise()
    6310            self._match_text_seq("ON", "CONVERSION", "ERROR")
    6311
    6312        if self._match_set((TokenType.FORMAT, TokenType.COMMA)):
    6313            fmt_string = self._parse_string()
    6314            fmt = self._parse_at_time_zone(fmt_string)
    6315
    6316            if not to:
    6317                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
    6318            if to.this in exp.DataType.TEMPORAL_TYPES:
    6319                this = self.expression(
    6320                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
    6321                    this=this,
    6322                    format=exp.Literal.string(
    6323                        format_time(
    6324                            fmt_string.this if fmt_string else "",
    6325                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
    6326                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
    6327                        )
    6328                    ),
    6329                    safe=safe,
    6330                )
    6331
    6332                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
    6333                    this.set("zone", fmt.args["zone"])
    6334                return this
    6335        elif not to:
    6336            self.raise_error("Expected TYPE after CAST")
    6337        elif isinstance(to, exp.Identifier):
    6338            to = exp.DataType.build(to.name, udt=True)
    6339        elif to.this == exp.DataType.Type.CHAR:
    6340            if self._match(TokenType.CHARACTER_SET):
    6341                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
    6342
    6343        return self.expression(
    6344            exp.Cast if strict else exp.TryCast,
    6345            this=this,
    6346            to=to,
    6347            format=fmt,
    6348            safe=safe,
    6349            action=self._parse_var_from_options(self.CAST_ACTIONS, raise_unmatched=False),
    6350            default=default,
    6351        )
    6352
    6353    def _parse_string_agg(self) -> exp.GroupConcat:
    6354        if self._match(TokenType.DISTINCT):
    6355            args: t.List[t.Optional[exp.Expression]] = [
    6356                self.expression(exp.Distinct, expressions=[self._parse_assignment()])
    6357            ]
    6358            if self._match(TokenType.COMMA):
    6359                args.extend(self._parse_csv(self._parse_assignment))
    6360        else:
    6361            args = self._parse_csv(self._parse_assignment)  # type: ignore
    6362
    6363        if self._match_text_seq("ON", "OVERFLOW"):
    6364            # trino: LISTAGG(expression [, separator] [ON OVERFLOW overflow_behavior])
    6365            if self._match_text_seq("ERROR"):
    6366                on_overflow: t.Optional[exp.Expression] = exp.var("ERROR")
    6367            else:
    6368                self._match_text_seq("TRUNCATE")
    6369                on_overflow = self.expression(
    6370                    exp.OverflowTruncateBehavior,
    6371                    this=self._parse_string(),
    6372                    with_count=(
    6373                        self._match_text_seq("WITH", "COUNT")
    6374                        or not self._match_text_seq("WITHOUT", "COUNT")
    6375                    ),
    6376                )
    6377        else:
    6378            on_overflow = None
    6379
    6380        index = self._index
    6381        if not self._match(TokenType.R_PAREN) and args:
    6382            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
    6383            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
    6384            # The order is parsed through `this` as a canonicalization for WITHIN GROUPs
    6385            args[0] = self._parse_limit(this=self._parse_order(this=args[0]))
    6386            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
    6387
    6388        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
    6389        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
    6390        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
    6391        if not self._match_text_seq("WITHIN", "GROUP"):
    6392            self._retreat(index)
    6393            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
    6394
    6395        # The corresponding match_r_paren will be called in parse_function (caller)
    6396        self._match_l_paren()
    6397
    6398        return self.expression(
    6399            exp.GroupConcat,
    6400            this=self._parse_order(this=seq_get(args, 0)),
    6401            separator=seq_get(args, 1),
    6402            on_overflow=on_overflow,
    6403        )
    6404
    6405    def _parse_convert(
    6406        self, strict: bool, safe: t.Optional[bool] = None
    6407    ) -> t.Optional[exp.Expression]:
    6408        this = self._parse_bitwise()
    6409
    6410        if self._match(TokenType.USING):
    6411            to: t.Optional[exp.Expression] = self.expression(
    6412                exp.CharacterSet, this=self._parse_var()
    6413            )
    6414        elif self._match(TokenType.COMMA):
    6415            to = self._parse_types()
    6416        else:
    6417            to = None
    6418
    6419        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
    6420
    6421    def _parse_xml_table(self) -> exp.XMLTable:
    6422        namespaces = None
    6423        passing = None
    6424        columns = None
    6425
    6426        if self._match_text_seq("XMLNAMESPACES", "("):
    6427            namespaces = self._parse_xml_namespace()
    6428            self._match_text_seq(")", ",")
    6429
    6430        this = self._parse_string()
    6431
    6432        if self._match_text_seq("PASSING"):
    6433            # The BY VALUE keywords are optional and are provided for semantic clarity
    6434            self._match_text_seq("BY", "VALUE")
    6435            passing = self._parse_csv(self._parse_column)
    6436
    6437        by_ref = self._match_text_seq("RETURNING", "SEQUENCE", "BY", "REF")
    6438
    6439        if self._match_text_seq("COLUMNS"):
    6440            columns = self._parse_csv(self._parse_field_def)
    6441
    6442        return self.expression(
    6443            exp.XMLTable,
    6444            this=this,
    6445            namespaces=namespaces,
    6446            passing=passing,
    6447            columns=columns,
    6448            by_ref=by_ref,
    6449        )
    6450
    6451    def _parse_xml_namespace(self) -> t.List[exp.XMLNamespace]:
    6452        namespaces = []
    6453
    6454        while True:
    6455            if self._match(TokenType.DEFAULT):
    6456                uri = self._parse_string()
    6457            else:
    6458                uri = self._parse_alias(self._parse_string())
    6459            namespaces.append(self.expression(exp.XMLNamespace, this=uri))
    6460            if not self._match(TokenType.COMMA):
    6461                break
    6462
    6463        return namespaces
    6464
    6465    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
    6466        """
    6467        There are generally two variants of the DECODE function:
    6468
    6469        - DECODE(bin, charset)
    6470        - DECODE(expression, search, result [, search, result] ... [, default])
    6471
    6472        The second variant will always be parsed into a CASE expression. Note that NULL
    6473        needs special treatment, since we need to explicitly check for it with `IS NULL`,
    6474        instead of relying on pattern matching.
    6475        """
    6476        args = self._parse_csv(self._parse_assignment)
    6477
    6478        if len(args) < 3:
    6479            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
    6480
    6481        expression, *expressions = args
    6482        if not expression:
    6483            return None
    6484
    6485        ifs = []
    6486        for search, result in zip(expressions[::2], expressions[1::2]):
    6487            if not search or not result:
    6488                return None
    6489
    6490            if isinstance(search, exp.Literal):
    6491                ifs.append(
    6492                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
    6493                )
    6494            elif isinstance(search, exp.Null):
    6495                ifs.append(
    6496                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
    6497                )
    6498            else:
    6499                cond = exp.or_(
    6500                    exp.EQ(this=expression.copy(), expression=search),
    6501                    exp.and_(
    6502                        exp.Is(this=expression.copy(), expression=exp.Null()),
    6503                        exp.Is(this=search.copy(), expression=exp.Null()),
    6504                        copy=False,
    6505                    ),
    6506                    copy=False,
    6507                )
    6508                ifs.append(exp.If(this=cond, true=result))
    6509
    6510        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
    6511
    6512    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
    6513        self._match_text_seq("KEY")
    6514        key = self._parse_column()
    6515        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
    6516        self._match_text_seq("VALUE")
    6517        value = self._parse_bitwise()
    6518
    6519        if not key and not value:
    6520            return None
    6521        return self.expression(exp.JSONKeyValue, this=key, expression=value)
    6522
    6523    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    6524        if not this or not self._match_text_seq("FORMAT", "JSON"):
    6525            return this
    6526
    6527        return self.expression(exp.FormatJson, this=this)
    6528
    6529    def _parse_on_condition(self) -> t.Optional[exp.OnCondition]:
    6530        # MySQL uses "X ON EMPTY Y ON ERROR" (e.g. JSON_VALUE) while Oracle uses the opposite (e.g. JSON_EXISTS)
    6531        if self.dialect.ON_CONDITION_EMPTY_BEFORE_ERROR:
    6532            empty = self._parse_on_handling("EMPTY", *self.ON_CONDITION_TOKENS)
    6533            error = self._parse_on_handling("ERROR", *self.ON_CONDITION_TOKENS)
    6534        else:
    6535            error = self._parse_on_handling("ERROR", *self.ON_CONDITION_TOKENS)
    6536            empty = self._parse_on_handling("EMPTY", *self.ON_CONDITION_TOKENS)
    6537
    6538        null = self._parse_on_handling("NULL", *self.ON_CONDITION_TOKENS)
    6539
    6540        if not empty and not error and not null:
    6541            return None
    6542
    6543        return self.expression(
    6544            exp.OnCondition,
    6545            empty=empty,
    6546            error=error,
    6547            null=null,
    6548        )
    6549
    6550    def _parse_on_handling(
    6551        self, on: str, *values: str
    6552    ) -> t.Optional[str] | t.Optional[exp.Expression]:
    6553        # Parses the "X ON Y" or "DEFAULT <expr> ON Y syntax, e.g. NULL ON NULL (Oracle, T-SQL, MySQL)
    6554        for value in values:
    6555            if self._match_text_seq(value, "ON", on):
    6556                return f"{value} ON {on}"
    6557
    6558        index = self._index
    6559        if self._match(TokenType.DEFAULT):
    6560            default_value = self._parse_bitwise()
    6561            if self._match_text_seq("ON", on):
    6562                return default_value
    6563
    6564            self._retreat(index)
    6565
    6566        return None
    6567
    6568    @t.overload
    6569    def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
    6570
    6571    @t.overload
    6572    def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
    6573
    6574    def _parse_json_object(self, agg=False):
    6575        star = self._parse_star()
    6576        expressions = (
    6577            [star]
    6578            if star
    6579            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
    6580        )
    6581        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
    6582
    6583        unique_keys = None
    6584        if self._match_text_seq("WITH", "UNIQUE"):
    6585            unique_keys = True
    6586        elif self._match_text_seq("WITHOUT", "UNIQUE"):
    6587            unique_keys = False
    6588
    6589        self._match_text_seq("KEYS")
    6590
    6591        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
    6592            self._parse_type()
    6593        )
    6594        encoding = self._match_text_seq("ENCODING") and self._parse_var()
    6595
    6596        return self.expression(
    6597            exp.JSONObjectAgg if agg else exp.JSONObject,
    6598            expressions=expressions,
    6599            null_handling=null_handling,
    6600            unique_keys=unique_keys,
    6601            return_type=return_type,
    6602            encoding=encoding,
    6603        )
    6604
    6605    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
    6606    def _parse_json_column_def(self) -> exp.JSONColumnDef:
    6607        if not self._match_text_seq("NESTED"):
    6608            this = self._parse_id_var()
    6609            kind = self._parse_types(allow_identifiers=False)
    6610            nested = None
    6611        else:
    6612            this = None
    6613            kind = None
    6614            nested = True
    6615
    6616        path = self._match_text_seq("PATH") and self._parse_string()
    6617        nested_schema = nested and self._parse_json_schema()
    6618
    6619        return self.expression(
    6620            exp.JSONColumnDef,
    6621            this=this,
    6622            kind=kind,
    6623            path=path,
    6624            nested_schema=nested_schema,
    6625        )
    6626
    6627    def _parse_json_schema(self) -> exp.JSONSchema:
    6628        self._match_text_seq("COLUMNS")
    6629        return self.expression(
    6630            exp.JSONSchema,
    6631            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
    6632        )
    6633
    6634    def _parse_json_table(self) -> exp.JSONTable:
    6635        this = self._parse_format_json(self._parse_bitwise())
    6636        path = self._match(TokenType.COMMA) and self._parse_string()
    6637        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
    6638        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
    6639        schema = self._parse_json_schema()
    6640
    6641        return exp.JSONTable(
    6642            this=this,
    6643            schema=schema,
    6644            path=path,
    6645            error_handling=error_handling,
    6646            empty_handling=empty_handling,
    6647        )
    6648
    6649    def _parse_match_against(self) -> exp.MatchAgainst:
    6650        expressions = self._parse_csv(self._parse_column)
    6651
    6652        self._match_text_seq(")", "AGAINST", "(")
    6653
    6654        this = self._parse_string()
    6655
    6656        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
    6657            modifier = "IN NATURAL LANGUAGE MODE"
    6658            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
    6659                modifier = f"{modifier} WITH QUERY EXPANSION"
    6660        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
    6661            modifier = "IN BOOLEAN MODE"
    6662        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
    6663            modifier = "WITH QUERY EXPANSION"
    6664        else:
    6665            modifier = None
    6666
    6667        return self.expression(
    6668            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
    6669        )
    6670
    6671    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
    6672    def _parse_open_json(self) -> exp.OpenJSON:
    6673        this = self._parse_bitwise()
    6674        path = self._match(TokenType.COMMA) and self._parse_string()
    6675
    6676        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
    6677            this = self._parse_field(any_token=True)
    6678            kind = self._parse_types()
    6679            path = self._parse_string()
    6680            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
    6681
    6682            return self.expression(
    6683                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
    6684            )
    6685
    6686        expressions = None
    6687        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
    6688            self._match_l_paren()
    6689            expressions = self._parse_csv(_parse_open_json_column_def)
    6690
    6691        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
    6692
    6693    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
    6694        args = self._parse_csv(self._parse_bitwise)
    6695
    6696        if self._match(TokenType.IN):
    6697            return self.expression(
    6698                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
    6699            )
    6700
    6701        if haystack_first:
    6702            haystack = seq_get(args, 0)
    6703            needle = seq_get(args, 1)
    6704        else:
    6705            haystack = seq_get(args, 1)
    6706            needle = seq_get(args, 0)
    6707
    6708        return self.expression(
    6709            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
    6710        )
    6711
    6712    def _parse_predict(self) -> exp.Predict:
    6713        self._match_text_seq("MODEL")
    6714        this = self._parse_table()
    6715
    6716        self._match(TokenType.COMMA)
    6717        self._match_text_seq("TABLE")
    6718
    6719        return self.expression(
    6720            exp.Predict,
    6721            this=this,
    6722            expression=self._parse_table(),
    6723            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
    6724        )
    6725
    6726    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
    6727        args = self._parse_csv(self._parse_table)
    6728        return exp.JoinHint(this=func_name.upper(), expressions=args)
    6729
    6730    def _parse_substring(self) -> exp.Substring:
    6731        # Postgres supports the form: substring(string [from int] [for int])
    6732        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
    6733
    6734        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
    6735
    6736        if self._match(TokenType.FROM):
    6737            args.append(self._parse_bitwise())
    6738        if self._match(TokenType.FOR):
    6739            if len(args) == 1:
    6740                args.append(exp.Literal.number(1))
    6741            args.append(self._parse_bitwise())
    6742
    6743        return self.validate_expression(exp.Substring.from_arg_list(args), args)
    6744
    6745    def _parse_trim(self) -> exp.Trim:
    6746        # https://www.w3resource.com/sql/character-functions/trim.php
    6747        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
    6748
    6749        position = None
    6750        collation = None
    6751        expression = None
    6752
    6753        if self._match_texts(self.TRIM_TYPES):
    6754            position = self._prev.text.upper()
    6755
    6756        this = self._parse_bitwise()
    6757        if self._match_set((TokenType.FROM, TokenType.COMMA)):
    6758            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
    6759            expression = self._parse_bitwise()
    6760
    6761            if invert_order:
    6762                this, expression = expression, this
    6763
    6764        if self._match(TokenType.COLLATE):
    6765            collation = self._parse_bitwise()
    6766
    6767        return self.expression(
    6768            exp.Trim, this=this, position=position, expression=expression, collation=collation
    6769        )
    6770
    6771    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
    6772        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
    6773
    6774    def _parse_named_window(self) -> t.Optional[exp.Expression]:
    6775        return self._parse_window(self._parse_id_var(), alias=True)
    6776
    6777    def _parse_respect_or_ignore_nulls(
    6778        self, this: t.Optional[exp.Expression]
    6779    ) -> t.Optional[exp.Expression]:
    6780        if self._match_text_seq("IGNORE", "NULLS"):
    6781            return self.expression(exp.IgnoreNulls, this=this)
    6782        if self._match_text_seq("RESPECT", "NULLS"):
    6783            return self.expression(exp.RespectNulls, this=this)
    6784        return this
    6785
    6786    def _parse_having_max(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    6787        if self._match(TokenType.HAVING):
    6788            self._match_texts(("MAX", "MIN"))
    6789            max = self._prev.text.upper() != "MIN"
    6790            return self.expression(
    6791                exp.HavingMax, this=this, expression=self._parse_column(), max=max
    6792            )
    6793
    6794        return this
    6795
    6796    def _parse_window(
    6797        self, this: t.Optional[exp.Expression], alias: bool = False
    6798    ) -> t.Optional[exp.Expression]:
    6799        func = this
    6800        comments = func.comments if isinstance(func, exp.Expression) else None
    6801
    6802        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
    6803        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
    6804        if self._match_text_seq("WITHIN", "GROUP"):
    6805            order = self._parse_wrapped(self._parse_order)
    6806            this = self.expression(exp.WithinGroup, this=this, expression=order)
    6807
    6808        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
    6809            self._match(TokenType.WHERE)
    6810            this = self.expression(
    6811                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
    6812            )
    6813            self._match_r_paren()
    6814
    6815        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
    6816        # Some dialects choose to implement and some do not.
    6817        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
    6818
    6819        # There is some code above in _parse_lambda that handles
    6820        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
    6821
    6822        # The below changes handle
    6823        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
    6824
    6825        # Oracle allows both formats
    6826        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
    6827        #   and Snowflake chose to do the same for familiarity
    6828        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
    6829        if isinstance(this, exp.AggFunc):
    6830            ignore_respect = this.find(exp.IgnoreNulls, exp.RespectNulls)
    6831
    6832            if ignore_respect and ignore_respect is not this:
    6833                ignore_respect.replace(ignore_respect.this)
    6834                this = self.expression(ignore_respect.__class__, this=this)
    6835
    6836        this = self._parse_respect_or_ignore_nulls(this)
    6837
    6838        # bigquery select from window x AS (partition by ...)
    6839        if alias:
    6840            over = None
    6841            self._match(TokenType.ALIAS)
    6842        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
    6843            return this
    6844        else:
    6845            over = self._prev.text.upper()
    6846
    6847        if comments and isinstance(func, exp.Expression):
    6848            func.pop_comments()
    6849
    6850        if not self._match(TokenType.L_PAREN):
    6851            return self.expression(
    6852                exp.Window,
    6853                comments=comments,
    6854                this=this,
    6855                alias=self._parse_id_var(False),
    6856                over=over,
    6857            )
    6858
    6859        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
    6860
    6861        first = self._match(TokenType.FIRST)
    6862        if self._match_text_seq("LAST"):
    6863            first = False
    6864
    6865        partition, order = self._parse_partition_and_order()
    6866        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
    6867
    6868        if kind:
    6869            self._match(TokenType.BETWEEN)
    6870            start = self._parse_window_spec()
    6871            self._match(TokenType.AND)
    6872            end = self._parse_window_spec()
    6873
    6874            spec = self.expression(
    6875                exp.WindowSpec,
    6876                kind=kind,
    6877                start=start["value"],
    6878                start_side=start["side"],
    6879                end=end["value"],
    6880                end_side=end["side"],
    6881            )
    6882        else:
    6883            spec = None
    6884
    6885        self._match_r_paren()
    6886
    6887        window = self.expression(
    6888            exp.Window,
    6889            comments=comments,
    6890            this=this,
    6891            partition_by=partition,
    6892            order=order,
    6893            spec=spec,
    6894            alias=window_alias,
    6895            over=over,
    6896            first=first,
    6897        )
    6898
    6899        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
    6900        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
    6901            return self._parse_window(window, alias=alias)
    6902
    6903        return window
    6904
    6905    def _parse_partition_and_order(
    6906        self,
    6907    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
    6908        return self._parse_partition_by(), self._parse_order()
    6909
    6910    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
    6911        self._match(TokenType.BETWEEN)
    6912
    6913        return {
    6914            "value": (
    6915                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
    6916                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
    6917                or self._parse_bitwise()
    6918            ),
    6919            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
    6920        }
    6921
    6922    def _parse_alias(
    6923        self, this: t.Optional[exp.Expression], explicit: bool = False
    6924    ) -> t.Optional[exp.Expression]:
    6925        # In some dialects, LIMIT and OFFSET can act as both identifiers and keywords (clauses)
    6926        # so this section tries to parse the clause version and if it fails, it treats the token
    6927        # as an identifier (alias)
    6928        if self._can_parse_limit_or_offset():
    6929            return this
    6930
    6931        any_token = self._match(TokenType.ALIAS)
    6932        comments = self._prev_comments or []
    6933
    6934        if explicit and not any_token:
    6935            return this
    6936
    6937        if self._match(TokenType.L_PAREN):
    6938            aliases = self.expression(
    6939                exp.Aliases,
    6940                comments=comments,
    6941                this=this,
    6942                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
    6943            )
    6944            self._match_r_paren(aliases)
    6945            return aliases
    6946
    6947        alias = self._parse_id_var(any_token, tokens=self.ALIAS_TOKENS) or (
    6948            self.STRING_ALIASES and self._parse_string_as_identifier()
    6949        )
    6950
    6951        if alias:
    6952            comments.extend(alias.pop_comments())
    6953            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
    6954            column = this.this
    6955
    6956            # Moves the comment next to the alias in `expr /* comment */ AS alias`
    6957            if not this.comments and column and column.comments:
    6958                this.comments = column.pop_comments()
    6959
    6960        return this
    6961
    6962    def _parse_id_var(
    6963        self,
    6964        any_token: bool = True,
    6965        tokens: t.Optional[t.Collection[TokenType]] = None,
    6966    ) -> t.Optional[exp.Expression]:
    6967        expression = self._parse_identifier()
    6968        if not expression and (
    6969            (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS)
    6970        ):
    6971            quoted = self._prev.token_type == TokenType.STRING
    6972            expression = self.expression(exp.Identifier, this=self._prev.text, quoted=quoted)
    6973
    6974        return expression
    6975
    6976    def _parse_string(self) -> t.Optional[exp.Expression]:
    6977        if self._match_set(self.STRING_PARSERS):
    6978            return self.STRING_PARSERS[self._prev.token_type](self, self._prev)
    6979        return self._parse_placeholder()
    6980
    6981    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
    6982        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
    6983
    6984    def _parse_number(self) -> t.Optional[exp.Expression]:
    6985        if self._match_set(self.NUMERIC_PARSERS):
    6986            return self.NUMERIC_PARSERS[self._prev.token_type](self, self._prev)
    6987        return self._parse_placeholder()
    6988
    6989    def _parse_identifier(self) -> t.Optional[exp.Expression]:
    6990        if self._match(TokenType.IDENTIFIER):
    6991            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
    6992        return self._parse_placeholder()
    6993
    6994    def _parse_var(
    6995        self,
    6996        any_token: bool = False,
    6997        tokens: t.Optional[t.Collection[TokenType]] = None,
    6998        upper: bool = False,
    6999    ) -> t.Optional[exp.Expression]:
    7000        if (
    7001            (any_token and self._advance_any())
    7002            or self._match(TokenType.VAR)
    7003            or (self._match_set(tokens) if tokens else False)
    7004        ):
    7005            return self.expression(
    7006                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
    7007            )
    7008        return self._parse_placeholder()
    7009
    7010    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
    7011        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
    7012            self._advance()
    7013            return self._prev
    7014        return None
    7015
    7016    def _parse_var_or_string(self, upper: bool = False) -> t.Optional[exp.Expression]:
    7017        return self._parse_string() or self._parse_var(any_token=True, upper=upper)
    7018
    7019    def _parse_primary_or_var(self) -> t.Optional[exp.Expression]:
    7020        return self._parse_primary() or self._parse_var(any_token=True)
    7021
    7022    def _parse_null(self) -> t.Optional[exp.Expression]:
    7023        if self._match_set(self.NULL_TOKENS):
    7024            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
    7025        return self._parse_placeholder()
    7026
    7027    def _parse_boolean(self) -> t.Optional[exp.Expression]:
    7028        if self._match(TokenType.TRUE):
    7029            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
    7030        if self._match(TokenType.FALSE):
    7031            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
    7032        return self._parse_placeholder()
    7033
    7034    def _parse_star(self) -> t.Optional[exp.Expression]:
    7035        if self._match(TokenType.STAR):
    7036            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
    7037        return self._parse_placeholder()
    7038
    7039    def _parse_parameter(self) -> exp.Parameter:
    7040        this = self._parse_identifier() or self._parse_primary_or_var()
    7041        return self.expression(exp.Parameter, this=this)
    7042
    7043    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
    7044        if self._match_set(self.PLACEHOLDER_PARSERS):
    7045            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
    7046            if placeholder:
    7047                return placeholder
    7048            self._advance(-1)
    7049        return None
    7050
    7051    def _parse_star_op(self, *keywords: str) -> t.Optional[t.List[exp.Expression]]:
    7052        if not self._match_texts(keywords):
    7053            return None
    7054        if self._match(TokenType.L_PAREN, advance=False):
    7055            return self._parse_wrapped_csv(self._parse_expression)
    7056
    7057        expression = self._parse_expression()
    7058        return [expression] if expression else None
    7059
    7060    def _parse_csv(
    7061        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
    7062    ) -> t.List[exp.Expression]:
    7063        parse_result = parse_method()
    7064        items = [parse_result] if parse_result is not None else []
    7065
    7066        while self._match(sep):
    7067            self._add_comments(parse_result)
    7068            parse_result = parse_method()
    7069            if parse_result is not None:
    7070                items.append(parse_result)
    7071
    7072        return items
    7073
    7074    def _parse_tokens(
    7075        self, parse_method: t.Callable, expressions: t.Dict
    7076    ) -> t.Optional[exp.Expression]:
    7077        this = parse_method()
    7078
    7079        while self._match_set(expressions):
    7080            this = self.expression(
    7081                expressions[self._prev.token_type],
    7082                this=this,
    7083                comments=self._prev_comments,
    7084                expression=parse_method(),
    7085            )
    7086
    7087        return this
    7088
    7089    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
    7090        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
    7091
    7092    def _parse_wrapped_csv(
    7093        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
    7094    ) -> t.List[exp.Expression]:
    7095        return self._parse_wrapped(
    7096            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
    7097        )
    7098
    7099    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
    7100        wrapped = self._match(TokenType.L_PAREN)
    7101        if not wrapped and not optional:
    7102            self.raise_error("Expecting (")
    7103        parse_result = parse_method()
    7104        if wrapped:
    7105            self._match_r_paren()
    7106        return parse_result
    7107
    7108    def _parse_expressions(self) -> t.List[exp.Expression]:
    7109        return self._parse_csv(self._parse_expression)
    7110
    7111    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
    7112        return self._parse_select() or self._parse_set_operations(
    7113            self._parse_alias(self._parse_assignment(), explicit=True)
    7114            if alias
    7115            else self._parse_assignment()
    7116        )
    7117
    7118    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
    7119        return self._parse_query_modifiers(
    7120            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
    7121        )
    7122
    7123    def _parse_transaction(self) -> exp.Transaction | exp.Command:
    7124        this = None
    7125        if self._match_texts(self.TRANSACTION_KIND):
    7126            this = self._prev.text
    7127
    7128        self._match_texts(("TRANSACTION", "WORK"))
    7129
    7130        modes = []
    7131        while True:
    7132            mode = []
    7133            while self._match(TokenType.VAR):
    7134                mode.append(self._prev.text)
    7135
    7136            if mode:
    7137                modes.append(" ".join(mode))
    7138            if not self._match(TokenType.COMMA):
    7139                break
    7140
    7141        return self.expression(exp.Transaction, this=this, modes=modes)
    7142
    7143    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
    7144        chain = None
    7145        savepoint = None
    7146        is_rollback = self._prev.token_type == TokenType.ROLLBACK
    7147
    7148        self._match_texts(("TRANSACTION", "WORK"))
    7149
    7150        if self._match_text_seq("TO"):
    7151            self._match_text_seq("SAVEPOINT")
    7152            savepoint = self._parse_id_var()
    7153
    7154        if self._match(TokenType.AND):
    7155            chain = not self._match_text_seq("NO")
    7156            self._match_text_seq("CHAIN")
    7157
    7158        if is_rollback:
    7159            return self.expression(exp.Rollback, savepoint=savepoint)
    7160
    7161        return self.expression(exp.Commit, chain=chain)
    7162
    7163    def _parse_refresh(self) -> exp.Refresh:
    7164        self._match(TokenType.TABLE)
    7165        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
    7166
    7167    def _parse_add_column(self) -> t.Optional[exp.Expression]:
    7168        if not self._match_text_seq("ADD"):
    7169            return None
    7170
    7171        self._match(TokenType.COLUMN)
    7172        exists_column = self._parse_exists(not_=True)
    7173        expression = self._parse_field_def()
    7174
    7175        if expression:
    7176            expression.set("exists", exists_column)
    7177
    7178            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
    7179            if self._match_texts(("FIRST", "AFTER")):
    7180                position = self._prev.text
    7181                column_position = self.expression(
    7182                    exp.ColumnPosition, this=self._parse_column(), position=position
    7183                )
    7184                expression.set("position", column_position)
    7185
    7186        return expression
    7187
    7188    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
    7189        drop = self._match(TokenType.DROP) and self._parse_drop()
    7190        if drop and not isinstance(drop, exp.Command):
    7191            drop.set("kind", drop.args.get("kind", "COLUMN"))
    7192        return drop
    7193
    7194    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
    7195    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
    7196        return self.expression(
    7197            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
    7198        )
    7199
    7200    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
    7201        index = self._index - 1
    7202
    7203        if self._match_set(self.ADD_CONSTRAINT_TOKENS, advance=False):
    7204            return self._parse_csv(
    7205                lambda: self.expression(
    7206                    exp.AddConstraint, expressions=self._parse_csv(self._parse_constraint)
    7207                )
    7208            )
    7209
    7210        self._retreat(index)
    7211        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
    7212            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
    7213
    7214        if self._match_text_seq("ADD", "COLUMNS"):
    7215            schema = self._parse_schema()
    7216            if schema:
    7217                return [schema]
    7218            return []
    7219
    7220        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
    7221
    7222    def _parse_alter_table_alter(self) -> t.Optional[exp.Expression]:
    7223        if self._match_texts(self.ALTER_ALTER_PARSERS):
    7224            return self.ALTER_ALTER_PARSERS[self._prev.text.upper()](self)
    7225
    7226        # Many dialects support the ALTER [COLUMN] syntax, so if there is no
    7227        # keyword after ALTER we default to parsing this statement
    7228        self._match(TokenType.COLUMN)
    7229        column = self._parse_field(any_token=True)
    7230
    7231        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
    7232            return self.expression(exp.AlterColumn, this=column, drop=True)
    7233        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
    7234            return self.expression(exp.AlterColumn, this=column, default=self._parse_assignment())
    7235        if self._match(TokenType.COMMENT):
    7236            return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
    7237        if self._match_text_seq("DROP", "NOT", "NULL"):
    7238            return self.expression(
    7239                exp.AlterColumn,
    7240                this=column,
    7241                drop=True,
    7242                allow_null=True,
    7243            )
    7244        if self._match_text_seq("SET", "NOT", "NULL"):
    7245            return self.expression(
    7246                exp.AlterColumn,
    7247                this=column,
    7248                allow_null=False,
    7249            )
    7250
    7251        if self._match_text_seq("SET", "VISIBLE"):
    7252            return self.expression(exp.AlterColumn, this=column, visible="VISIBLE")
    7253        if self._match_text_seq("SET", "INVISIBLE"):
    7254            return self.expression(exp.AlterColumn, this=column, visible="INVISIBLE")
    7255
    7256        self._match_text_seq("SET", "DATA")
    7257        self._match_text_seq("TYPE")
    7258        return self.expression(
    7259            exp.AlterColumn,
    7260            this=column,
    7261            dtype=self._parse_types(),
    7262            collate=self._match(TokenType.COLLATE) and self._parse_term(),
    7263            using=self._match(TokenType.USING) and self._parse_assignment(),
    7264        )
    7265
    7266    def _parse_alter_diststyle(self) -> exp.AlterDistStyle:
    7267        if self._match_texts(("ALL", "EVEN", "AUTO")):
    7268            return self.expression(exp.AlterDistStyle, this=exp.var(self._prev.text.upper()))
    7269
    7270        self._match_text_seq("KEY", "DISTKEY")
    7271        return self.expression(exp.AlterDistStyle, this=self._parse_column())
    7272
    7273    def _parse_alter_sortkey(self, compound: t.Optional[bool] = None) -> exp.AlterSortKey:
    7274        if compound:
    7275            self._match_text_seq("SORTKEY")
    7276
    7277        if self._match(TokenType.L_PAREN, advance=False):
    7278            return self.expression(
    7279                exp.AlterSortKey, expressions=self._parse_wrapped_id_vars(), compound=compound
    7280            )
    7281
    7282        self._match_texts(("AUTO", "NONE"))
    7283        return self.expression(
    7284            exp.AlterSortKey, this=exp.var(self._prev.text.upper()), compound=compound
    7285        )
    7286
    7287    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
    7288        index = self._index - 1
    7289
    7290        partition_exists = self._parse_exists()
    7291        if self._match(TokenType.PARTITION, advance=False):
    7292            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
    7293
    7294        self._retreat(index)
    7295        return self._parse_csv(self._parse_drop_column)
    7296
    7297    def _parse_alter_table_rename(self) -> t.Optional[exp.AlterRename | exp.RenameColumn]:
    7298        if self._match(TokenType.COLUMN):
    7299            exists = self._parse_exists()
    7300            old_column = self._parse_column()
    7301            to = self._match_text_seq("TO")
    7302            new_column = self._parse_column()
    7303
    7304            if old_column is None or to is None or new_column is None:
    7305                return None
    7306
    7307            return self.expression(exp.RenameColumn, this=old_column, to=new_column, exists=exists)
    7308
    7309        self._match_text_seq("TO")
    7310        return self.expression(exp.AlterRename, this=self._parse_table(schema=True))
    7311
    7312    def _parse_alter_table_set(self) -> exp.AlterSet:
    7313        alter_set = self.expression(exp.AlterSet)
    7314
    7315        if self._match(TokenType.L_PAREN, advance=False) or self._match_text_seq(
    7316            "TABLE", "PROPERTIES"
    7317        ):
    7318            alter_set.set("expressions", self._parse_wrapped_csv(self._parse_assignment))
    7319        elif self._match_text_seq("FILESTREAM_ON", advance=False):
    7320            alter_set.set("expressions", [self._parse_assignment()])
    7321        elif self._match_texts(("LOGGED", "UNLOGGED")):
    7322            alter_set.set("option", exp.var(self._prev.text.upper()))
    7323        elif self._match_text_seq("WITHOUT") and self._match_texts(("CLUSTER", "OIDS")):
    7324            alter_set.set("option", exp.var(f"WITHOUT {self._prev.text.upper()}"))
    7325        elif self._match_text_seq("LOCATION"):
    7326            alter_set.set("location", self._parse_field())
    7327        elif self._match_text_seq("ACCESS", "METHOD"):
    7328            alter_set.set("access_method", self._parse_field())
    7329        elif self._match_text_seq("TABLESPACE"):
    7330            alter_set.set("tablespace", self._parse_field())
    7331        elif self._match_text_seq("FILE", "FORMAT") or self._match_text_seq("FILEFORMAT"):
    7332            alter_set.set("file_format", [self._parse_field()])
    7333        elif self._match_text_seq("STAGE_FILE_FORMAT"):
    7334            alter_set.set("file_format", self._parse_wrapped_options())
    7335        elif self._match_text_seq("STAGE_COPY_OPTIONS"):
    7336            alter_set.set("copy_options", self._parse_wrapped_options())
    7337        elif self._match_text_seq("TAG") or self._match_text_seq("TAGS"):
    7338            alter_set.set("tag", self._parse_csv(self._parse_assignment))
    7339        else:
    7340            if self._match_text_seq("SERDE"):
    7341                alter_set.set("serde", self._parse_field())
    7342
    7343            alter_set.set("expressions", [self._parse_properties()])
    7344
    7345        return alter_set
    7346
    7347    def _parse_alter(self) -> exp.Alter | exp.Command:
    7348        start = self._prev
    7349
    7350        alter_token = self._match_set(self.ALTERABLES) and self._prev
    7351        if not alter_token:
    7352            return self._parse_as_command(start)
    7353
    7354        exists = self._parse_exists()
    7355        only = self._match_text_seq("ONLY")
    7356        this = self._parse_table(schema=True)
    7357        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
    7358
    7359        if self._next:
    7360            self._advance()
    7361
    7362        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
    7363        if parser:
    7364            actions = ensure_list(parser(self))
    7365            not_valid = self._match_text_seq("NOT", "VALID")
    7366            options = self._parse_csv(self._parse_property)
    7367
    7368            if not self._curr and actions:
    7369                return self.expression(
    7370                    exp.Alter,
    7371                    this=this,
    7372                    kind=alter_token.text.upper(),
    7373                    exists=exists,
    7374                    actions=actions,
    7375                    only=only,
    7376                    options=options,
    7377                    cluster=cluster,
    7378                    not_valid=not_valid,
    7379                )
    7380
    7381        return self._parse_as_command(start)
    7382
    7383    def _parse_analyze(self) -> exp.Analyze | exp.Command:
    7384        start = self._prev
    7385        # https://duckdb.org/docs/sql/statements/analyze
    7386        if not self._curr:
    7387            return self.expression(exp.Analyze)
    7388
    7389        options = []
    7390        while self._match_texts(self.ANALYZE_STYLES):
    7391            if self._prev.text.upper() == "BUFFER_USAGE_LIMIT":
    7392                options.append(f"BUFFER_USAGE_LIMIT {self._parse_number()}")
    7393            else:
    7394                options.append(self._prev.text.upper())
    7395
    7396        this: t.Optional[exp.Expression] = None
    7397        inner_expression: t.Optional[exp.Expression] = None
    7398
    7399        kind = self._curr and self._curr.text.upper()
    7400
    7401        if self._match(TokenType.TABLE) or self._match(TokenType.INDEX):
    7402            this = self._parse_table_parts()
    7403        elif self._match_text_seq("TABLES"):
    7404            if self._match_set((TokenType.FROM, TokenType.IN)):
    7405                kind = f"{kind} {self._prev.text.upper()}"
    7406                this = self._parse_table(schema=True, is_db_reference=True)
    7407        elif self._match_text_seq("DATABASE"):
    7408            this = self._parse_table(schema=True, is_db_reference=True)
    7409        elif self._match_text_seq("CLUSTER"):
    7410            this = self._parse_table()
    7411        # Try matching inner expr keywords before fallback to parse table.
    7412        elif self._match_texts(self.ANALYZE_EXPRESSION_PARSERS):
    7413            kind = None
    7414            inner_expression = self.ANALYZE_EXPRESSION_PARSERS[self._prev.text.upper()](self)
    7415        else:
    7416            # Empty kind  https://prestodb.io/docs/current/sql/analyze.html
    7417            kind = None
    7418            this = self._parse_table_parts()
    7419
    7420        partition = self._try_parse(self._parse_partition)
    7421        if not partition and self._match_texts(self.PARTITION_KEYWORDS):
    7422            return self._parse_as_command(start)
    7423
    7424        # https://docs.starrocks.io/docs/sql-reference/sql-statements/cbo_stats/ANALYZE_TABLE/
    7425        if self._match_text_seq("WITH", "SYNC", "MODE") or self._match_text_seq(
    7426            "WITH", "ASYNC", "MODE"
    7427        ):
    7428            mode = f"WITH {self._tokens[self._index - 2].text.upper()} MODE"
    7429        else:
    7430            mode = None
    7431
    7432        if self._match_texts(self.ANALYZE_EXPRESSION_PARSERS):
    7433            inner_expression = self.ANALYZE_EXPRESSION_PARSERS[self._prev.text.upper()](self)
    7434
    7435        properties = self._parse_properties()
    7436        return self.expression(
    7437            exp.Analyze,
    7438            kind=kind,
    7439            this=this,
    7440            mode=mode,
    7441            partition=partition,
    7442            properties=properties,
    7443            expression=inner_expression,
    7444            options=options,
    7445        )
    7446
    7447    # https://spark.apache.org/docs/3.5.1/sql-ref-syntax-aux-analyze-table.html
    7448    def _parse_analyze_statistics(self) -> exp.AnalyzeStatistics:
    7449        this = None
    7450        kind = self._prev.text.upper()
    7451        option = self._prev.text.upper() if self._match_text_seq("DELTA") else None
    7452        expressions = []
    7453
    7454        if not self._match_text_seq("STATISTICS"):
    7455            self.raise_error("Expecting token STATISTICS")
    7456
    7457        if self._match_text_seq("NOSCAN"):
    7458            this = "NOSCAN"
    7459        elif self._match(TokenType.FOR):
    7460            if self._match_text_seq("ALL", "COLUMNS"):
    7461                this = "FOR ALL COLUMNS"
    7462            if self._match_texts("COLUMNS"):
    7463                this = "FOR COLUMNS"
    7464                expressions = self._parse_csv(self._parse_column_reference)
    7465        elif self._match_text_seq("SAMPLE"):
    7466            sample = self._parse_number()
    7467            expressions = [
    7468                self.expression(
    7469                    exp.AnalyzeSample,
    7470                    sample=sample,
    7471                    kind=self._prev.text.upper() if self._match(TokenType.PERCENT) else None,
    7472                )
    7473            ]
    7474
    7475        return self.expression(
    7476            exp.AnalyzeStatistics, kind=kind, option=option, this=this, expressions=expressions
    7477        )
    7478
    7479    # https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/ANALYZE.html
    7480    def _parse_analyze_validate(self) -> exp.AnalyzeValidate:
    7481        kind = None
    7482        this = None
    7483        expression: t.Optional[exp.Expression] = None
    7484        if self._match_text_seq("REF", "UPDATE"):
    7485            kind = "REF"
    7486            this = "UPDATE"
    7487            if self._match_text_seq("SET", "DANGLING", "TO", "NULL"):
    7488                this = "UPDATE SET DANGLING TO NULL"
    7489        elif self._match_text_seq("STRUCTURE"):
    7490            kind = "STRUCTURE"
    7491            if self._match_text_seq("CASCADE", "FAST"):
    7492                this = "CASCADE FAST"
    7493            elif self._match_text_seq("CASCADE", "COMPLETE") and self._match_texts(
    7494                ("ONLINE", "OFFLINE")
    7495            ):
    7496                this = f"CASCADE COMPLETE {self._prev.text.upper()}"
    7497                expression = self._parse_into()
    7498
    7499        return self.expression(exp.AnalyzeValidate, kind=kind, this=this, expression=expression)
    7500
    7501    def _parse_analyze_columns(self) -> t.Optional[exp.AnalyzeColumns]:
    7502        this = self._prev.text.upper()
    7503        if self._match_text_seq("COLUMNS"):
    7504            return self.expression(exp.AnalyzeColumns, this=f"{this} {self._prev.text.upper()}")
    7505        return None
    7506
    7507    def _parse_analyze_delete(self) -> t.Optional[exp.AnalyzeDelete]:
    7508        kind = self._prev.text.upper() if self._match_text_seq("SYSTEM") else None
    7509        if self._match_text_seq("STATISTICS"):
    7510            return self.expression(exp.AnalyzeDelete, kind=kind)
    7511        return None
    7512
    7513    def _parse_analyze_list(self) -> t.Optional[exp.AnalyzeListChainedRows]:
    7514        if self._match_text_seq("CHAINED", "ROWS"):
    7515            return self.expression(exp.AnalyzeListChainedRows, expression=self._parse_into())
    7516        return None
    7517
    7518    # https://dev.mysql.com/doc/refman/8.4/en/analyze-table.html
    7519    def _parse_analyze_histogram(self) -> exp.AnalyzeHistogram:
    7520        this = self._prev.text.upper()
    7521        expression: t.Optional[exp.Expression] = None
    7522        expressions = []
    7523        update_options = None
    7524
    7525        if self._match_text_seq("HISTOGRAM", "ON"):
    7526            expressions = self._parse_csv(self._parse_column_reference)
    7527            with_expressions = []
    7528            while self._match(TokenType.WITH):
    7529                # https://docs.starrocks.io/docs/sql-reference/sql-statements/cbo_stats/ANALYZE_TABLE/
    7530                if self._match_texts(("SYNC", "ASYNC")):
    7531                    if self._match_text_seq("MODE", advance=False):
    7532                        with_expressions.append(f"{self._prev.text.upper()} MODE")
    7533                        self._advance()
    7534                else:
    7535                    buckets = self._parse_number()
    7536                    if self._match_text_seq("BUCKETS"):
    7537                        with_expressions.append(f"{buckets} BUCKETS")
    7538            if with_expressions:
    7539                expression = self.expression(exp.AnalyzeWith, expressions=with_expressions)
    7540
    7541            if self._match_texts(("MANUAL", "AUTO")) and self._match(
    7542                TokenType.UPDATE, advance=False
    7543            ):
    7544                update_options = self._prev.text.upper()
    7545                self._advance()
    7546            elif self._match_text_seq("USING", "DATA"):
    7547                expression = self.expression(exp.UsingData, this=self._parse_string())
    7548
    7549        return self.expression(
    7550            exp.AnalyzeHistogram,
    7551            this=this,
    7552            expressions=expressions,
    7553            expression=expression,
    7554            update_options=update_options,
    7555        )
    7556
    7557    def _parse_merge(self) -> exp.Merge:
    7558        self._match(TokenType.INTO)
    7559        target = self._parse_table()
    7560
    7561        if target and self._match(TokenType.ALIAS, advance=False):
    7562            target.set("alias", self._parse_table_alias())
    7563
    7564        self._match(TokenType.USING)
    7565        using = self._parse_table()
    7566
    7567        self._match(TokenType.ON)
    7568        on = self._parse_assignment()
    7569
    7570        return self.expression(
    7571            exp.Merge,
    7572            this=target,
    7573            using=using,
    7574            on=on,
    7575            whens=self._parse_when_matched(),
    7576            returning=self._parse_returning(),
    7577        )
    7578
    7579    def _parse_when_matched(self) -> exp.Whens:
    7580        whens = []
    7581
    7582        while self._match(TokenType.WHEN):
    7583            matched = not self._match(TokenType.NOT)
    7584            self._match_text_seq("MATCHED")
    7585            source = (
    7586                False
    7587                if self._match_text_seq("BY", "TARGET")
    7588                else self._match_text_seq("BY", "SOURCE")
    7589            )
    7590            condition = self._parse_assignment() if self._match(TokenType.AND) else None
    7591
    7592            self._match(TokenType.THEN)
    7593
    7594            if self._match(TokenType.INSERT):
    7595                this = self._parse_star()
    7596                if this:
    7597                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=this)
    7598                else:
    7599                    then = self.expression(
    7600                        exp.Insert,
    7601                        this=exp.var("ROW")
    7602                        if self._match_text_seq("ROW")
    7603                        else self._parse_value(values=False),
    7604                        expression=self._match_text_seq("VALUES") and self._parse_value(),
    7605                    )
    7606            elif self._match(TokenType.UPDATE):
    7607                expressions = self._parse_star()
    7608                if expressions:
    7609                    then = self.expression(exp.Update, expressions=expressions)
    7610                else:
    7611                    then = self.expression(
    7612                        exp.Update,
    7613                        expressions=self._match(TokenType.SET)
    7614                        and self._parse_csv(self._parse_equality),
    7615                    )
    7616            elif self._match(TokenType.DELETE):
    7617                then = self.expression(exp.Var, this=self._prev.text)
    7618            else:
    7619                then = self._parse_var_from_options(self.CONFLICT_ACTIONS)
    7620
    7621            whens.append(
    7622                self.expression(
    7623                    exp.When,
    7624                    matched=matched,
    7625                    source=source,
    7626                    condition=condition,
    7627                    then=then,
    7628                )
    7629            )
    7630        return self.expression(exp.Whens, expressions=whens)
    7631
    7632    def _parse_show(self) -> t.Optional[exp.Expression]:
    7633        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
    7634        if parser:
    7635            return parser(self)
    7636        return self._parse_as_command(self._prev)
    7637
    7638    def _parse_set_item_assignment(
    7639        self, kind: t.Optional[str] = None
    7640    ) -> t.Optional[exp.Expression]:
    7641        index = self._index
    7642
    7643        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
    7644            return self._parse_set_transaction(global_=kind == "GLOBAL")
    7645
    7646        left = self._parse_primary() or self._parse_column()
    7647        assignment_delimiter = self._match_texts(("=", "TO"))
    7648
    7649        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
    7650            self._retreat(index)
    7651            return None
    7652
    7653        right = self._parse_statement() or self._parse_id_var()
    7654        if isinstance(right, (exp.Column, exp.Identifier)):
    7655            right = exp.var(right.name)
    7656
    7657        this = self.expression(exp.EQ, this=left, expression=right)
    7658        return self.expression(exp.SetItem, this=this, kind=kind)
    7659
    7660    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
    7661        self._match_text_seq("TRANSACTION")
    7662        characteristics = self._parse_csv(
    7663            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
    7664        )
    7665        return self.expression(
    7666            exp.SetItem,
    7667            expressions=characteristics,
    7668            kind="TRANSACTION",
    7669            **{"global": global_},  # type: ignore
    7670        )
    7671
    7672    def _parse_set_item(self) -> t.Optional[exp.Expression]:
    7673        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
    7674        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
    7675
    7676    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
    7677        index = self._index
    7678        set_ = self.expression(
    7679            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
    7680        )
    7681
    7682        if self._curr:
    7683            self._retreat(index)
    7684            return self._parse_as_command(self._prev)
    7685
    7686        return set_
    7687
    7688    def _parse_var_from_options(
    7689        self, options: OPTIONS_TYPE, raise_unmatched: bool = True
    7690    ) -> t.Optional[exp.Var]:
    7691        start = self._curr
    7692        if not start:
    7693            return None
    7694
    7695        option = start.text.upper()
    7696        continuations = options.get(option)
    7697
    7698        index = self._index
    7699        self._advance()
    7700        for keywords in continuations or []:
    7701            if isinstance(keywords, str):
    7702                keywords = (keywords,)
    7703
    7704            if self._match_text_seq(*keywords):
    7705                option = f"{option} {' '.join(keywords)}"
    7706                break
    7707        else:
    7708            if continuations or continuations is None:
    7709                if raise_unmatched:
    7710                    self.raise_error(f"Unknown option {option}")
    7711
    7712                self._retreat(index)
    7713                return None
    7714
    7715        return exp.var(option)
    7716
    7717    def _parse_as_command(self, start: Token) -> exp.Command:
    7718        while self._curr:
    7719            self._advance()
    7720        text = self._find_sql(start, self._prev)
    7721        size = len(start.text)
    7722        self._warn_unsupported()
    7723        return exp.Command(this=text[:size], expression=text[size:])
    7724
    7725    def _parse_dict_property(self, this: str) -> exp.DictProperty:
    7726        settings = []
    7727
    7728        self._match_l_paren()
    7729        kind = self._parse_id_var()
    7730
    7731        if self._match(TokenType.L_PAREN):
    7732            while True:
    7733                key = self._parse_id_var()
    7734                value = self._parse_primary()
    7735                if not key and value is None:
    7736                    break
    7737                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
    7738            self._match(TokenType.R_PAREN)
    7739
    7740        self._match_r_paren()
    7741
    7742        return self.expression(
    7743            exp.DictProperty,
    7744            this=this,
    7745            kind=kind.this if kind else None,
    7746            settings=settings,
    7747        )
    7748
    7749    def _parse_dict_range(self, this: str) -> exp.DictRange:
    7750        self._match_l_paren()
    7751        has_min = self._match_text_seq("MIN")
    7752        if has_min:
    7753            min = self._parse_var() or self._parse_primary()
    7754            self._match_text_seq("MAX")
    7755            max = self._parse_var() or self._parse_primary()
    7756        else:
    7757            max = self._parse_var() or self._parse_primary()
    7758            min = exp.Literal.number(0)
    7759        self._match_r_paren()
    7760        return self.expression(exp.DictRange, this=this, min=min, max=max)
    7761
    7762    def _parse_comprehension(
    7763        self, this: t.Optional[exp.Expression]
    7764    ) -> t.Optional[exp.Comprehension]:
    7765        index = self._index
    7766        expression = self._parse_column()
    7767        if not self._match(TokenType.IN):
    7768            self._retreat(index - 1)
    7769            return None
    7770        iterator = self._parse_column()
    7771        condition = self._parse_assignment() if self._match_text_seq("IF") else None
    7772        return self.expression(
    7773            exp.Comprehension,
    7774            this=this,
    7775            expression=expression,
    7776            iterator=iterator,
    7777            condition=condition,
    7778        )
    7779
    7780    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
    7781        if self._match(TokenType.HEREDOC_STRING):
    7782            return self.expression(exp.Heredoc, this=self._prev.text)
    7783
    7784        if not self._match_text_seq("$"):
    7785            return None
    7786
    7787        tags = ["$"]
    7788        tag_text = None
    7789
    7790        if self._is_connected():
    7791            self._advance()
    7792            tags.append(self._prev.text.upper())
    7793        else:
    7794            self.raise_error("No closing $ found")
    7795
    7796        if tags[-1] != "$":
    7797            if self._is_connected() and self._match_text_seq("$"):
    7798                tag_text = tags[-1]
    7799                tags.append("$")
    7800            else:
    7801                self.raise_error("No closing $ found")
    7802
    7803        heredoc_start = self._curr
    7804
    7805        while self._curr:
    7806            if self._match_text_seq(*tags, advance=False):
    7807                this = self._find_sql(heredoc_start, self._prev)
    7808                self._advance(len(tags))
    7809                return self.expression(exp.Heredoc, this=this, tag=tag_text)
    7810
    7811            self._advance()
    7812
    7813        self.raise_error(f"No closing {''.join(tags)} found")
    7814        return None
    7815
    7816    def _find_parser(
    7817        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
    7818    ) -> t.Optional[t.Callable]:
    7819        if not self._curr:
    7820            return None
    7821
    7822        index = self._index
    7823        this = []
    7824        while True:
    7825            # The current token might be multiple words
    7826            curr = self._curr.text.upper()
    7827            key = curr.split(" ")
    7828            this.append(curr)
    7829
    7830            self._advance()
    7831            result, trie = in_trie(trie, key)
    7832            if result == TrieResult.FAILED:
    7833                break
    7834
    7835            if result == TrieResult.EXISTS:
    7836                subparser = parsers[" ".join(this)]
    7837                return subparser
    7838
    7839        self._retreat(index)
    7840        return None
    7841
    7842    def _match(self, token_type, advance=True, expression=None):
    7843        if not self._curr:
    7844            return None
    7845
    7846        if self._curr.token_type == token_type:
    7847            if advance:
    7848                self._advance()
    7849            self._add_comments(expression)
    7850            return True
    7851
    7852        return None
    7853
    7854    def _match_set(self, types, advance=True):
    7855        if not self._curr:
    7856            return None
    7857
    7858        if self._curr.token_type in types:
    7859            if advance:
    7860                self._advance()
    7861            return True
    7862
    7863        return None
    7864
    7865    def _match_pair(self, token_type_a, token_type_b, advance=True):
    7866        if not self._curr or not self._next:
    7867            return None
    7868
    7869        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
    7870            if advance:
    7871                self._advance(2)
    7872            return True
    7873
    7874        return None
    7875
    7876    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
    7877        if not self._match(TokenType.L_PAREN, expression=expression):
    7878            self.raise_error("Expecting (")
    7879
    7880    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
    7881        if not self._match(TokenType.R_PAREN, expression=expression):
    7882            self.raise_error("Expecting )")
    7883
    7884    def _match_texts(self, texts, advance=True):
    7885        if (
    7886            self._curr
    7887            and self._curr.token_type != TokenType.STRING
    7888            and self._curr.text.upper() in texts
    7889        ):
    7890            if advance:
    7891                self._advance()
    7892            return True
    7893        return None
    7894
    7895    def _match_text_seq(self, *texts, advance=True):
    7896        index = self._index
    7897        for text in texts:
    7898            if (
    7899                self._curr
    7900                and self._curr.token_type != TokenType.STRING
    7901                and self._curr.text.upper() == text
    7902            ):
    7903                self._advance()
    7904            else:
    7905                self._retreat(index)
    7906                return None
    7907
    7908        if not advance:
    7909            self._retreat(index)
    7910
    7911        return True
    7912
    7913    def _replace_lambda(
    7914        self, node: t.Optional[exp.Expression], expressions: t.List[exp.Expression]
    7915    ) -> t.Optional[exp.Expression]:
    7916        if not node:
    7917            return node
    7918
    7919        lambda_types = {e.name: e.args.get("to") or False for e in expressions}
    7920
    7921        for column in node.find_all(exp.Column):
    7922            typ = lambda_types.get(column.parts[0].name)
    7923            if typ is not None:
    7924                dot_or_id = column.to_dot() if column.table else column.this
    7925
    7926                if typ:
    7927                    dot_or_id = self.expression(
    7928                        exp.Cast,
    7929                        this=dot_or_id,
    7930                        to=typ,
    7931                    )
    7932
    7933                parent = column.parent
    7934
    7935                while isinstance(parent, exp.Dot):
    7936                    if not isinstance(parent.parent, exp.Dot):
    7937                        parent.replace(dot_or_id)
    7938                        break
    7939                    parent = parent.parent
    7940                else:
    7941                    if column is node:
    7942                        node = dot_or_id
    7943                    else:
    7944                        column.replace(dot_or_id)
    7945        return node
    7946
    7947    def _parse_truncate_table(self) -> t.Optional[exp.TruncateTable] | exp.Expression:
    7948        start = self._prev
    7949
    7950        # Not to be confused with TRUNCATE(number, decimals) function call
    7951        if self._match(TokenType.L_PAREN):
    7952            self._retreat(self._index - 2)
    7953            return self._parse_function()
    7954
    7955        # Clickhouse supports TRUNCATE DATABASE as well
    7956        is_database = self._match(TokenType.DATABASE)
    7957
    7958        self._match(TokenType.TABLE)
    7959
    7960        exists = self._parse_exists(not_=False)
    7961
    7962        expressions = self._parse_csv(
    7963            lambda: self._parse_table(schema=True, is_db_reference=is_database)
    7964        )
    7965
    7966        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
    7967
    7968        if self._match_text_seq("RESTART", "IDENTITY"):
    7969            identity = "RESTART"
    7970        elif self._match_text_seq("CONTINUE", "IDENTITY"):
    7971            identity = "CONTINUE"
    7972        else:
    7973            identity = None
    7974
    7975        if self._match_text_seq("CASCADE") or self._match_text_seq("RESTRICT"):
    7976            option = self._prev.text
    7977        else:
    7978            option = None
    7979
    7980        partition = self._parse_partition()
    7981
    7982        # Fallback case
    7983        if self._curr:
    7984            return self._parse_as_command(start)
    7985
    7986        return self.expression(
    7987            exp.TruncateTable,
    7988            expressions=expressions,
    7989            is_database=is_database,
    7990            exists=exists,
    7991            cluster=cluster,
    7992            identity=identity,
    7993            option=option,
    7994            partition=partition,
    7995        )
    7996
    7997    def _parse_with_operator(self) -> t.Optional[exp.Expression]:
    7998        this = self._parse_ordered(self._parse_opclass)
    7999
    8000        if not self._match(TokenType.WITH):
    8001            return this
    8002
    8003        op = self._parse_var(any_token=True)
    8004
    8005        return self.expression(exp.WithOperator, this=this, op=op)
    8006
    8007    def _parse_wrapped_options(self) -> t.List[t.Optional[exp.Expression]]:
    8008        self._match(TokenType.EQ)
    8009        self._match(TokenType.L_PAREN)
    8010
    8011        opts: t.List[t.Optional[exp.Expression]] = []
    8012        option: exp.Expression | None
    8013        while self._curr and not self._match(TokenType.R_PAREN):
    8014            if self._match_text_seq("FORMAT_NAME", "="):
    8015                # The FORMAT_NAME can be set to an identifier for Snowflake and T-SQL
    8016                option = self._parse_format_name()
    8017            else:
    8018                option = self._parse_property()
    8019
    8020            if option is None:
    8021                self.raise_error("Unable to parse option")
    8022                break
    8023
    8024            opts.append(option)
    8025
    8026        return opts
    8027
    8028    def _parse_copy_parameters(self) -> t.List[exp.CopyParameter]:
    8029        sep = TokenType.COMMA if self.dialect.COPY_PARAMS_ARE_CSV else None
    8030
    8031        options = []
    8032        while self._curr and not self._match(TokenType.R_PAREN, advance=False):
    8033            option = self._parse_var(any_token=True)
    8034            prev = self._prev.text.upper()
    8035
    8036            # Different dialects might separate options and values by white space, "=" and "AS"
    8037            self._match(TokenType.EQ)
    8038            self._match(TokenType.ALIAS)
    8039
    8040            param = self.expression(exp.CopyParameter, this=option)
    8041
    8042            if prev in self.COPY_INTO_VARLEN_OPTIONS and self._match(
    8043                TokenType.L_PAREN, advance=False
    8044            ):
    8045                # Snowflake FILE_FORMAT case, Databricks COPY & FORMAT options
    8046                param.set("expressions", self._parse_wrapped_options())
    8047            elif prev == "FILE_FORMAT":
    8048                # T-SQL's external file format case
    8049                param.set("expression", self._parse_field())
    8050            else:
    8051                param.set("expression", self._parse_unquoted_field())
    8052
    8053            options.append(param)
    8054            self._match(sep)
    8055
    8056        return options
    8057
    8058    def _parse_credentials(self) -> t.Optional[exp.Credentials]:
    8059        expr = self.expression(exp.Credentials)
    8060
    8061        if self._match_text_seq("STORAGE_INTEGRATION", "="):
    8062            expr.set("storage", self._parse_field())
    8063        if self._match_text_seq("CREDENTIALS"):
    8064            # Snowflake case: CREDENTIALS = (...), Redshift case: CREDENTIALS <string>
    8065            creds = (
    8066                self._parse_wrapped_options() if self._match(TokenType.EQ) else self._parse_field()
    8067            )
    8068            expr.set("credentials", creds)
    8069        if self._match_text_seq("ENCRYPTION"):
    8070            expr.set("encryption", self._parse_wrapped_options())
    8071        if self._match_text_seq("IAM_ROLE"):
    8072            expr.set("iam_role", self._parse_field())
    8073        if self._match_text_seq("REGION"):
    8074            expr.set("region", self._parse_field())
    8075
    8076        return expr
    8077
    8078    def _parse_file_location(self) -> t.Optional[exp.Expression]:
    8079        return self._parse_field()
    8080
    8081    def _parse_copy(self) -> exp.Copy | exp.Command:
    8082        start = self._prev
    8083
    8084        self._match(TokenType.INTO)
    8085
    8086        this = (
    8087            self._parse_select(nested=True, parse_subquery_alias=False)
    8088            if self._match(TokenType.L_PAREN, advance=False)
    8089            else self._parse_table(schema=True)
    8090        )
    8091
    8092        kind = self._match(TokenType.FROM) or not self._match_text_seq("TO")
    8093
    8094        files = self._parse_csv(self._parse_file_location)
    8095        credentials = self._parse_credentials()
    8096
    8097        self._match_text_seq("WITH")
    8098
    8099        params = self._parse_wrapped(self._parse_copy_parameters, optional=True)
    8100
    8101        # Fallback case
    8102        if self._curr:
    8103            return self._parse_as_command(start)
    8104
    8105        return self.expression(
    8106            exp.Copy,
    8107            this=this,
    8108            kind=kind,
    8109            credentials=credentials,
    8110            files=files,
    8111            params=params,
    8112        )
    8113
    8114    def _parse_normalize(self) -> exp.Normalize:
    8115        return self.expression(
    8116            exp.Normalize,
    8117            this=self._parse_bitwise(),
    8118            form=self._match(TokenType.COMMA) and self._parse_var(),
    8119        )
    8120
    8121    def _parse_ceil_floor(self, expr_type: t.Type[TCeilFloor]) -> TCeilFloor:
    8122        args = self._parse_csv(lambda: self._parse_lambda())
    8123
    8124        this = seq_get(args, 0)
    8125        decimals = seq_get(args, 1)
    8126
    8127        return expr_type(
    8128            this=this, decimals=decimals, to=self._match_text_seq("TO") and self._parse_var()
    8129        )
    8130
    8131    def _parse_star_ops(self) -> t.Optional[exp.Expression]:
    8132        if self._match_text_seq("COLUMNS", "(", advance=False):
    8133            this = self._parse_function()
    8134            if isinstance(this, exp.Columns):
    8135                this.set("unpack", True)
    8136            return this
    8137
    8138        return self.expression(
    8139            exp.Star,
    8140            **{  # type: ignore
    8141                "except": self._parse_star_op("EXCEPT", "EXCLUDE"),
    8142                "replace": self._parse_star_op("REPLACE"),
    8143                "rename": self._parse_star_op("RENAME"),
    8144            },
    8145        )
    8146
    8147    def _parse_grant_privilege(self) -> t.Optional[exp.GrantPrivilege]:
    8148        privilege_parts = []
    8149
    8150        # Keep consuming consecutive keywords until comma (end of this privilege) or ON
    8151        # (end of privilege list) or L_PAREN (start of column list) are met
    8152        while self._curr and not self._match_set(self.PRIVILEGE_FOLLOW_TOKENS, advance=False):
    8153            privilege_parts.append(self._curr.text.upper())
    8154            self._advance()
    8155
    8156        this = exp.var(" ".join(privilege_parts))
    8157        expressions = (
    8158            self._parse_wrapped_csv(self._parse_column)
    8159            if self._match(TokenType.L_PAREN, advance=False)
    8160            else None
    8161        )
    8162
    8163        return self.expression(exp.GrantPrivilege, this=this, expressions=expressions)
    8164
    8165    def _parse_grant_principal(self) -> t.Optional[exp.GrantPrincipal]:
    8166        kind = self._match_texts(("ROLE", "GROUP")) and self._prev.text.upper()
    8167        principal = self._parse_id_var()
    8168
    8169        if not principal:
    8170            return None
    8171
    8172        return self.expression(exp.GrantPrincipal, this=principal, kind=kind)
    8173
    8174    def _parse_grant(self) -> exp.Grant | exp.Command:
    8175        start = self._prev
    8176
    8177        privileges = self._parse_csv(self._parse_grant_privilege)
    8178
    8179        self._match(TokenType.ON)
    8180        kind = self._match_set(self.CREATABLES) and self._prev.text.upper()
    8181
    8182        # Attempt to parse the securable e.g. MySQL allows names
    8183        # such as "foo.*", "*.*" which are not easily parseable yet
    8184        securable = self._try_parse(self._parse_table_parts)
    8185
    8186        if not securable or not self._match_text_seq("TO"):
    8187            return self._parse_as_command(start)
    8188
    8189        principals = self._parse_csv(self._parse_grant_principal)
    8190
    8191        grant_option = self._match_text_seq("WITH", "GRANT", "OPTION")
    8192
    8193        if self._curr:
    8194            return self._parse_as_command(start)
    8195
    8196        return self.expression(
    8197            exp.Grant,
    8198            privileges=privileges,
    8199            kind=kind,
    8200            securable=securable,
    8201            principals=principals,
    8202            grant_option=grant_option,
    8203        )
    8204
    8205    def _parse_overlay(self) -> exp.Overlay:
    8206        return self.expression(
    8207            exp.Overlay,
    8208            **{  # type: ignore
    8209                "this": self._parse_bitwise(),
    8210                "expression": self._match_text_seq("PLACING") and self._parse_bitwise(),
    8211                "from": self._match_text_seq("FROM") and self._parse_bitwise(),
    8212                "for": self._match_text_seq("FOR") and self._parse_bitwise(),
    8213            },
    8214        )
    8215
    8216    def _parse_format_name(self) -> exp.Property:
    8217        # Note: Although not specified in the docs, Snowflake does accept a string/identifier
    8218        # for FILE_FORMAT = <format_name>
    8219        return self.expression(
    8220            exp.Property,
    8221            this=exp.var("FORMAT_NAME"),
    8222            value=self._parse_string() or self._parse_table_parts(),
    8223        )

logger = <Logger sqlglot (WARNING)>
OPTIONS_TYPE = typing.Dict[str, typing.Sequence[typing.Union[typing.Sequence[str], str]]]
def build_var_map(args: List) -> sqlglot.expressions.StarMap | sqlglot.expressions.VarMap: View Source

    28def build_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
    29    if len(args) == 1 and args[0].is_star:
    30        return exp.StarMap(this=args[0])
    31
    32    keys = []
    33    values = []
    34    for i in range(0, len(args), 2):
    35        keys.append(args[i])
    36        values.append(args[i + 1])
    37
    38    return exp.VarMap(keys=exp.array(*keys, copy=False), values=exp.array(*values, copy=False))

def build_like(args: List) -> sqlglot.expressions.Escape | sqlglot.expressions.Like: View Source

    41def build_like(args: t.List) -> exp.Escape | exp.Like:
    42    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
    43    return exp.Escape(this=like, expression=seq_get(args, 2)) if len(args) > 2 else like

def binary_range_parser( expr_type: Type[sqlglot.expressions.Expression], reverse_args: bool = False) -> Callable[[Parser, Optional[sqlglot.expressions.Expression]], Optional[sqlglot.expressions.Expression]]: View Source

    46def binary_range_parser(
    47    expr_type: t.Type[exp.Expression], reverse_args: bool = False
    48) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
    49    def _parse_binary_range(
    50        self: Parser, this: t.Optional[exp.Expression]
    51    ) -> t.Optional[exp.Expression]:
    52        expression = self._parse_bitwise()
    53        if reverse_args:
    54            this, expression = expression, this
    55        return self._parse_escape(self.expression(expr_type, this=this, expression=expression))
    56
    57    return _parse_binary_range

def build_logarithm( args: List, dialect: sqlglot.dialects.Dialect) -> sqlglot.expressions.Func: View Source

    60def build_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
    61    # Default argument order is base, expression
    62    this = seq_get(args, 0)
    63    expression = seq_get(args, 1)
    64
    65    if expression:
    66        if not dialect.LOG_BASE_FIRST:
    67            this, expression = expression, this
    68        return exp.Log(this=this, expression=expression)
    69
    70    return (exp.Ln if dialect.parser_class.LOG_DEFAULTS_TO_LN else exp.Log)(this=this)

def build_hex( args: List, dialect: sqlglot.dialects.Dialect) -> sqlglot.expressions.Hex | sqlglot.expressions.LowerHex: View Source

    73def build_hex(args: t.List, dialect: Dialect) -> exp.Hex | exp.LowerHex:
    74    arg = seq_get(args, 0)
    75    return exp.LowerHex(this=arg) if dialect.HEX_LOWERCASE else exp.Hex(this=arg)

def build_lower(args: List) -> sqlglot.expressions.Lower | sqlglot.expressions.Hex: View Source

    78def build_lower(args: t.List) -> exp.Lower | exp.Hex:
    79    # LOWER(HEX(..)) can be simplified to LowerHex to simplify its transpilation
    80    arg = seq_get(args, 0)
    81    return exp.LowerHex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Lower(this=arg)

def build_upper(args: List) -> sqlglot.expressions.Upper | sqlglot.expressions.Hex: View Source

    84def build_upper(args: t.List) -> exp.Upper | exp.Hex:
    85    # UPPER(HEX(..)) can be simplified to Hex to simplify its transpilation
    86    arg = seq_get(args, 0)
    87    return exp.Hex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Upper(this=arg)

def build_extract_json_with_path( expr_type: Type[~E]) -> Callable[[List, sqlglot.dialects.Dialect], ~E]: View Source

     90def build_extract_json_with_path(expr_type: t.Type[E]) -> t.Callable[[t.List, Dialect], E]:
     91    def _builder(args: t.List, dialect: Dialect) -> E:
     92        expression = expr_type(
     93            this=seq_get(args, 0), expression=dialect.to_json_path(seq_get(args, 1))
     94        )
     95        if len(args) > 2 and expr_type is exp.JSONExtract:
     96            expression.set("expressions", args[2:])
     97
     98        return expression
     99
    100    return _builder

def build_mod(args: List) -> sqlglot.expressions.Mod: View Source

    103def build_mod(args: t.List) -> exp.Mod:
    104    this = seq_get(args, 0)
    105    expression = seq_get(args, 1)
    106
    107    # Wrap the operands if they are binary nodes, e.g. MOD(a + 1, 7) -> (a + 1) % 7
    108    this = exp.Paren(this=this) if isinstance(this, exp.Binary) else this
    109    expression = exp.Paren(this=expression) if isinstance(expression, exp.Binary) else expression
    110
    111    return exp.Mod(this=this, expression=expression)

def build_pad(args: List, is_left: bool = True): View Source

    114def build_pad(args: t.List, is_left: bool = True):
    115    return exp.Pad(
    116        this=seq_get(args, 0),
    117        expression=seq_get(args, 1),
    118        fill_pattern=seq_get(args, 2),
    119        is_left=is_left,
    120    )

def build_array_constructor( exp_class: Type[~E], args: List, bracket_kind: sqlglot.tokens.TokenType, dialect: sqlglot.dialects.Dialect) -> sqlglot.expressions.Expression: View Source

    123def build_array_constructor(
    124    exp_class: t.Type[E], args: t.List, bracket_kind: TokenType, dialect: Dialect
    125) -> exp.Expression:
    126    array_exp = exp_class(expressions=args)
    127
    128    if exp_class == exp.Array and dialect.HAS_DISTINCT_ARRAY_CONSTRUCTORS:
    129        array_exp.set("bracket_notation", bracket_kind == TokenType.L_BRACKET)
    130
    131    return array_exp

def build_convert_timezone( args: List, default_source_tz: Optional[str] = None) -> Union[sqlglot.expressions.ConvertTimezone, sqlglot.expressions.Anonymous]: View Source

    134def build_convert_timezone(
    135    args: t.List, default_source_tz: t.Optional[str] = None
    136) -> t.Union[exp.ConvertTimezone, exp.Anonymous]:
    137    if len(args) == 2:
    138        source_tz = exp.Literal.string(default_source_tz) if default_source_tz else None
    139        return exp.ConvertTimezone(
    140            source_tz=source_tz, target_tz=seq_get(args, 0), timestamp=seq_get(args, 1)
    141        )
    142
    143    return exp.ConvertTimezone.from_arg_list(args)

def build_trim(args: List, is_left: bool = True): View Source

    146def build_trim(args: t.List, is_left: bool = True):
    147    return exp.Trim(
    148        this=seq_get(args, 0),
    149        expression=seq_get(args, 1),
    150        position="LEADING" if is_left else "TRAILING",
    151    )

def build_coalesce( args: List, is_nvl: Optional[bool] = None) -> sqlglot.expressions.Coalesce: View Source

    154def build_coalesce(args: t.List, is_nvl: t.Optional[bool] = None) -> exp.Coalesce:
    155    return exp.Coalesce(this=seq_get(args, 0), expressions=args[1:], is_nvl=is_nvl)

def build_locate_strposition(args: List): View Source

    158def build_locate_strposition(args: t.List):
    159    return exp.StrPosition(
    160        this=seq_get(args, 1),
    161        substr=seq_get(args, 0),
    162        position=seq_get(args, 2),
    163    )

class Parser: View Source

     176class Parser(metaclass=_Parser):
     177    """
     178    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
     179
     180    Args:
     181        error_level: The desired error level.
     182            Default: ErrorLevel.IMMEDIATE
     183        error_message_context: The amount of context to capture from a query string when displaying
     184            the error message (in number of characters).
     185            Default: 100
     186        max_errors: Maximum number of error messages to include in a raised ParseError.
     187            This is only relevant if error_level is ErrorLevel.RAISE.
     188            Default: 3
     189    """
     190
     191    FUNCTIONS: t.Dict[str, t.Callable] = {
     192        **{name: func.from_arg_list for name, func in exp.FUNCTION_BY_NAME.items()},
     193        **dict.fromkeys(("COALESCE", "IFNULL", "NVL"), build_coalesce),
     194        "ARRAY": lambda args, dialect: exp.Array(expressions=args),
     195        "ARRAYAGG": lambda args, dialect: exp.ArrayAgg(
     196            this=seq_get(args, 0), nulls_excluded=dialect.ARRAY_AGG_INCLUDES_NULLS is None or None
     197        ),
     198        "ARRAY_AGG": lambda args, dialect: exp.ArrayAgg(
     199            this=seq_get(args, 0), nulls_excluded=dialect.ARRAY_AGG_INCLUDES_NULLS is None or None
     200        ),
     201        "CHAR": lambda args: exp.Chr(expressions=args),
     202        "CHR": lambda args: exp.Chr(expressions=args),
     203        "COUNT": lambda args: exp.Count(this=seq_get(args, 0), expressions=args[1:], big_int=True),
     204        "CONCAT": lambda args, dialect: exp.Concat(
     205            expressions=args,
     206            safe=not dialect.STRICT_STRING_CONCAT,
     207            coalesce=dialect.CONCAT_COALESCE,
     208        ),
     209        "CONCAT_WS": lambda args, dialect: exp.ConcatWs(
     210            expressions=args,
     211            safe=not dialect.STRICT_STRING_CONCAT,
     212            coalesce=dialect.CONCAT_COALESCE,
     213        ),
     214        "CONVERT_TIMEZONE": build_convert_timezone,
     215        "DATE_TO_DATE_STR": lambda args: exp.Cast(
     216            this=seq_get(args, 0),
     217            to=exp.DataType(this=exp.DataType.Type.TEXT),
     218        ),
     219        "GENERATE_DATE_ARRAY": lambda args: exp.GenerateDateArray(
     220            start=seq_get(args, 0),
     221            end=seq_get(args, 1),
     222            step=seq_get(args, 2) or exp.Interval(this=exp.Literal.string(1), unit=exp.var("DAY")),
     223        ),
     224        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
     225        "HEX": build_hex,
     226        "JSON_EXTRACT": build_extract_json_with_path(exp.JSONExtract),
     227        "JSON_EXTRACT_SCALAR": build_extract_json_with_path(exp.JSONExtractScalar),
     228        "JSON_EXTRACT_PATH_TEXT": build_extract_json_with_path(exp.JSONExtractScalar),
     229        "LIKE": build_like,
     230        "LOG": build_logarithm,
     231        "LOG2": lambda args: exp.Log(this=exp.Literal.number(2), expression=seq_get(args, 0)),
     232        "LOG10": lambda args: exp.Log(this=exp.Literal.number(10), expression=seq_get(args, 0)),
     233        "LOWER": build_lower,
     234        "LPAD": lambda args: build_pad(args),
     235        "LEFTPAD": lambda args: build_pad(args),
     236        "LTRIM": lambda args: build_trim(args),
     237        "MOD": build_mod,
     238        "RIGHTPAD": lambda args: build_pad(args, is_left=False),
     239        "RPAD": lambda args: build_pad(args, is_left=False),
     240        "RTRIM": lambda args: build_trim(args, is_left=False),
     241        "SCOPE_RESOLUTION": lambda args: exp.ScopeResolution(expression=seq_get(args, 0))
     242        if len(args) != 2
     243        else exp.ScopeResolution(this=seq_get(args, 0), expression=seq_get(args, 1)),
     244        "STRPOS": exp.StrPosition.from_arg_list,
     245        "CHARINDEX": lambda args: build_locate_strposition(args),
     246        "INSTR": exp.StrPosition.from_arg_list,
     247        "LOCATE": lambda args: build_locate_strposition(args),
     248        "TIME_TO_TIME_STR": lambda args: exp.Cast(
     249            this=seq_get(args, 0),
     250            to=exp.DataType(this=exp.DataType.Type.TEXT),
     251        ),
     252        "TO_HEX": build_hex,
     253        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
     254            this=exp.Cast(
     255                this=seq_get(args, 0),
     256                to=exp.DataType(this=exp.DataType.Type.TEXT),
     257            ),
     258            start=exp.Literal.number(1),
     259            length=exp.Literal.number(10),
     260        ),
     261        "UNNEST": lambda args: exp.Unnest(expressions=ensure_list(seq_get(args, 0))),
     262        "UPPER": build_upper,
     263        "VAR_MAP": build_var_map,
     264    }
     265
     266    NO_PAREN_FUNCTIONS = {
     267        TokenType.CURRENT_DATE: exp.CurrentDate,
     268        TokenType.CURRENT_DATETIME: exp.CurrentDate,
     269        TokenType.CURRENT_TIME: exp.CurrentTime,
     270        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
     271        TokenType.CURRENT_USER: exp.CurrentUser,
     272    }
     273
     274    STRUCT_TYPE_TOKENS = {
     275        TokenType.NESTED,
     276        TokenType.OBJECT,
     277        TokenType.STRUCT,
     278        TokenType.UNION,
     279    }
     280
     281    NESTED_TYPE_TOKENS = {
     282        TokenType.ARRAY,
     283        TokenType.LIST,
     284        TokenType.LOWCARDINALITY,
     285        TokenType.MAP,
     286        TokenType.NULLABLE,
     287        TokenType.RANGE,
     288        *STRUCT_TYPE_TOKENS,
     289    }
     290
     291    ENUM_TYPE_TOKENS = {
     292        TokenType.DYNAMIC,
     293        TokenType.ENUM,
     294        TokenType.ENUM8,
     295        TokenType.ENUM16,
     296    }
     297
     298    AGGREGATE_TYPE_TOKENS = {
     299        TokenType.AGGREGATEFUNCTION,
     300        TokenType.SIMPLEAGGREGATEFUNCTION,
     301    }
     302
     303    TYPE_TOKENS = {
     304        TokenType.BIT,
     305        TokenType.BOOLEAN,
     306        TokenType.TINYINT,
     307        TokenType.UTINYINT,
     308        TokenType.SMALLINT,
     309        TokenType.USMALLINT,
     310        TokenType.INT,
     311        TokenType.UINT,
     312        TokenType.BIGINT,
     313        TokenType.UBIGINT,
     314        TokenType.INT128,
     315        TokenType.UINT128,
     316        TokenType.INT256,
     317        TokenType.UINT256,
     318        TokenType.MEDIUMINT,
     319        TokenType.UMEDIUMINT,
     320        TokenType.FIXEDSTRING,
     321        TokenType.FLOAT,
     322        TokenType.DOUBLE,
     323        TokenType.UDOUBLE,
     324        TokenType.CHAR,
     325        TokenType.NCHAR,
     326        TokenType.VARCHAR,
     327        TokenType.NVARCHAR,
     328        TokenType.BPCHAR,
     329        TokenType.TEXT,
     330        TokenType.MEDIUMTEXT,
     331        TokenType.LONGTEXT,
     332        TokenType.BLOB,
     333        TokenType.MEDIUMBLOB,
     334        TokenType.LONGBLOB,
     335        TokenType.BINARY,
     336        TokenType.VARBINARY,
     337        TokenType.JSON,
     338        TokenType.JSONB,
     339        TokenType.INTERVAL,
     340        TokenType.TINYBLOB,
     341        TokenType.TINYTEXT,
     342        TokenType.TIME,
     343        TokenType.TIMETZ,
     344        TokenType.TIMESTAMP,
     345        TokenType.TIMESTAMP_S,
     346        TokenType.TIMESTAMP_MS,
     347        TokenType.TIMESTAMP_NS,
     348        TokenType.TIMESTAMPTZ,
     349        TokenType.TIMESTAMPLTZ,
     350        TokenType.TIMESTAMPNTZ,
     351        TokenType.DATETIME,
     352        TokenType.DATETIME2,
     353        TokenType.DATETIME64,
     354        TokenType.SMALLDATETIME,
     355        TokenType.DATE,
     356        TokenType.DATE32,
     357        TokenType.INT4RANGE,
     358        TokenType.INT4MULTIRANGE,
     359        TokenType.INT8RANGE,
     360        TokenType.INT8MULTIRANGE,
     361        TokenType.NUMRANGE,
     362        TokenType.NUMMULTIRANGE,
     363        TokenType.TSRANGE,
     364        TokenType.TSMULTIRANGE,
     365        TokenType.TSTZRANGE,
     366        TokenType.TSTZMULTIRANGE,
     367        TokenType.DATERANGE,
     368        TokenType.DATEMULTIRANGE,
     369        TokenType.DECIMAL,
     370        TokenType.DECIMAL32,
     371        TokenType.DECIMAL64,
     372        TokenType.DECIMAL128,
     373        TokenType.DECIMAL256,
     374        TokenType.UDECIMAL,
     375        TokenType.BIGDECIMAL,
     376        TokenType.UUID,
     377        TokenType.GEOGRAPHY,
     378        TokenType.GEOMETRY,
     379        TokenType.POINT,
     380        TokenType.RING,
     381        TokenType.LINESTRING,
     382        TokenType.MULTILINESTRING,
     383        TokenType.POLYGON,
     384        TokenType.MULTIPOLYGON,
     385        TokenType.HLLSKETCH,
     386        TokenType.HSTORE,
     387        TokenType.PSEUDO_TYPE,
     388        TokenType.SUPER,
     389        TokenType.SERIAL,
     390        TokenType.SMALLSERIAL,
     391        TokenType.BIGSERIAL,
     392        TokenType.XML,
     393        TokenType.YEAR,
     394        TokenType.USERDEFINED,
     395        TokenType.MONEY,
     396        TokenType.SMALLMONEY,
     397        TokenType.ROWVERSION,
     398        TokenType.IMAGE,
     399        TokenType.VARIANT,
     400        TokenType.VECTOR,
     401        TokenType.OBJECT,
     402        TokenType.OBJECT_IDENTIFIER,
     403        TokenType.INET,
     404        TokenType.IPADDRESS,
     405        TokenType.IPPREFIX,
     406        TokenType.IPV4,
     407        TokenType.IPV6,
     408        TokenType.UNKNOWN,
     409        TokenType.NOTHING,
     410        TokenType.NULL,
     411        TokenType.NAME,
     412        TokenType.TDIGEST,
     413        TokenType.DYNAMIC,
     414        *ENUM_TYPE_TOKENS,
     415        *NESTED_TYPE_TOKENS,
     416        *AGGREGATE_TYPE_TOKENS,
     417    }
     418
     419    SIGNED_TO_UNSIGNED_TYPE_TOKEN = {
     420        TokenType.BIGINT: TokenType.UBIGINT,
     421        TokenType.INT: TokenType.UINT,
     422        TokenType.MEDIUMINT: TokenType.UMEDIUMINT,
     423        TokenType.SMALLINT: TokenType.USMALLINT,
     424        TokenType.TINYINT: TokenType.UTINYINT,
     425        TokenType.DECIMAL: TokenType.UDECIMAL,
     426        TokenType.DOUBLE: TokenType.UDOUBLE,
     427    }
     428
     429    SUBQUERY_PREDICATES = {
     430        TokenType.ANY: exp.Any,
     431        TokenType.ALL: exp.All,
     432        TokenType.EXISTS: exp.Exists,
     433        TokenType.SOME: exp.Any,
     434    }
     435
     436    RESERVED_TOKENS = {
     437        *Tokenizer.SINGLE_TOKENS.values(),
     438        TokenType.SELECT,
     439    } - {TokenType.IDENTIFIER}
     440
     441    DB_CREATABLES = {
     442        TokenType.DATABASE,
     443        TokenType.DICTIONARY,
     444        TokenType.FILE_FORMAT,
     445        TokenType.MODEL,
     446        TokenType.NAMESPACE,
     447        TokenType.SCHEMA,
     448        TokenType.SEQUENCE,
     449        TokenType.SINK,
     450        TokenType.SOURCE,
     451        TokenType.STAGE,
     452        TokenType.STORAGE_INTEGRATION,
     453        TokenType.STREAMLIT,
     454        TokenType.TABLE,
     455        TokenType.TAG,
     456        TokenType.VIEW,
     457        TokenType.WAREHOUSE,
     458    }
     459
     460    CREATABLES = {
     461        TokenType.COLUMN,
     462        TokenType.CONSTRAINT,
     463        TokenType.FOREIGN_KEY,
     464        TokenType.FUNCTION,
     465        TokenType.INDEX,
     466        TokenType.PROCEDURE,
     467        *DB_CREATABLES,
     468    }
     469
     470    ALTERABLES = {
     471        TokenType.INDEX,
     472        TokenType.TABLE,
     473        TokenType.VIEW,
     474    }
     475
     476    # Tokens that can represent identifiers
     477    ID_VAR_TOKENS = {
     478        TokenType.ALL,
     479        TokenType.ATTACH,
     480        TokenType.VAR,
     481        TokenType.ANTI,
     482        TokenType.APPLY,
     483        TokenType.ASC,
     484        TokenType.ASOF,
     485        TokenType.AUTO_INCREMENT,
     486        TokenType.BEGIN,
     487        TokenType.BPCHAR,
     488        TokenType.CACHE,
     489        TokenType.CASE,
     490        TokenType.COLLATE,
     491        TokenType.COMMAND,
     492        TokenType.COMMENT,
     493        TokenType.COMMIT,
     494        TokenType.CONSTRAINT,
     495        TokenType.COPY,
     496        TokenType.CUBE,
     497        TokenType.CURRENT_SCHEMA,
     498        TokenType.DEFAULT,
     499        TokenType.DELETE,
     500        TokenType.DESC,
     501        TokenType.DESCRIBE,
     502        TokenType.DETACH,
     503        TokenType.DICTIONARY,
     504        TokenType.DIV,
     505        TokenType.END,
     506        TokenType.EXECUTE,
     507        TokenType.EXPORT,
     508        TokenType.ESCAPE,
     509        TokenType.FALSE,
     510        TokenType.FIRST,
     511        TokenType.FILTER,
     512        TokenType.FINAL,
     513        TokenType.FORMAT,
     514        TokenType.FULL,
     515        TokenType.IDENTIFIER,
     516        TokenType.IS,
     517        TokenType.ISNULL,
     518        TokenType.INTERVAL,
     519        TokenType.KEEP,
     520        TokenType.KILL,
     521        TokenType.LEFT,
     522        TokenType.LIMIT,
     523        TokenType.LOAD,
     524        TokenType.MERGE,
     525        TokenType.NATURAL,
     526        TokenType.NEXT,
     527        TokenType.OFFSET,
     528        TokenType.OPERATOR,
     529        TokenType.ORDINALITY,
     530        TokenType.OVERLAPS,
     531        TokenType.OVERWRITE,
     532        TokenType.PARTITION,
     533        TokenType.PERCENT,
     534        TokenType.PIVOT,
     535        TokenType.PRAGMA,
     536        TokenType.PUT,
     537        TokenType.RANGE,
     538        TokenType.RECURSIVE,
     539        TokenType.REFERENCES,
     540        TokenType.REFRESH,
     541        TokenType.RENAME,
     542        TokenType.REPLACE,
     543        TokenType.RIGHT,
     544        TokenType.ROLLUP,
     545        TokenType.ROW,
     546        TokenType.ROWS,
     547        TokenType.SEMI,
     548        TokenType.SET,
     549        TokenType.SETTINGS,
     550        TokenType.SHOW,
     551        TokenType.TEMPORARY,
     552        TokenType.TOP,
     553        TokenType.TRUE,
     554        TokenType.TRUNCATE,
     555        TokenType.UNIQUE,
     556        TokenType.UNNEST,
     557        TokenType.UNPIVOT,
     558        TokenType.UPDATE,
     559        TokenType.USE,
     560        TokenType.VOLATILE,
     561        TokenType.WINDOW,
     562        *CREATABLES,
     563        *SUBQUERY_PREDICATES,
     564        *TYPE_TOKENS,
     565        *NO_PAREN_FUNCTIONS,
     566    }
     567    ID_VAR_TOKENS.remove(TokenType.UNION)
     568
     569    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
     570        TokenType.ANTI,
     571        TokenType.APPLY,
     572        TokenType.ASOF,
     573        TokenType.FULL,
     574        TokenType.LEFT,
     575        TokenType.LOCK,
     576        TokenType.NATURAL,
     577        TokenType.RIGHT,
     578        TokenType.SEMI,
     579        TokenType.WINDOW,
     580    }
     581
     582    ALIAS_TOKENS = ID_VAR_TOKENS
     583
     584    COLON_PLACEHOLDER_TOKENS = ID_VAR_TOKENS
     585
     586    ARRAY_CONSTRUCTORS = {
     587        "ARRAY": exp.Array,
     588        "LIST": exp.List,
     589    }
     590
     591    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
     592
     593    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
     594
     595    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
     596
     597    FUNC_TOKENS = {
     598        TokenType.COLLATE,
     599        TokenType.COMMAND,
     600        TokenType.CURRENT_DATE,
     601        TokenType.CURRENT_DATETIME,
     602        TokenType.CURRENT_SCHEMA,
     603        TokenType.CURRENT_TIMESTAMP,
     604        TokenType.CURRENT_TIME,
     605        TokenType.CURRENT_USER,
     606        TokenType.FILTER,
     607        TokenType.FIRST,
     608        TokenType.FORMAT,
     609        TokenType.GLOB,
     610        TokenType.IDENTIFIER,
     611        TokenType.INDEX,
     612        TokenType.ISNULL,
     613        TokenType.ILIKE,
     614        TokenType.INSERT,
     615        TokenType.LIKE,
     616        TokenType.MERGE,
     617        TokenType.NEXT,
     618        TokenType.OFFSET,
     619        TokenType.PRIMARY_KEY,
     620        TokenType.RANGE,
     621        TokenType.REPLACE,
     622        TokenType.RLIKE,
     623        TokenType.ROW,
     624        TokenType.UNNEST,
     625        TokenType.VAR,
     626        TokenType.LEFT,
     627        TokenType.RIGHT,
     628        TokenType.SEQUENCE,
     629        TokenType.DATE,
     630        TokenType.DATETIME,
     631        TokenType.TABLE,
     632        TokenType.TIMESTAMP,
     633        TokenType.TIMESTAMPTZ,
     634        TokenType.TRUNCATE,
     635        TokenType.WINDOW,
     636        TokenType.XOR,
     637        *TYPE_TOKENS,
     638        *SUBQUERY_PREDICATES,
     639    }
     640
     641    CONJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
     642        TokenType.AND: exp.And,
     643    }
     644
     645    ASSIGNMENT: t.Dict[TokenType, t.Type[exp.Expression]] = {
     646        TokenType.COLON_EQ: exp.PropertyEQ,
     647    }
     648
     649    DISJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
     650        TokenType.OR: exp.Or,
     651    }
     652
     653    EQUALITY = {
     654        TokenType.EQ: exp.EQ,
     655        TokenType.NEQ: exp.NEQ,
     656        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
     657    }
     658
     659    COMPARISON = {
     660        TokenType.GT: exp.GT,
     661        TokenType.GTE: exp.GTE,
     662        TokenType.LT: exp.LT,
     663        TokenType.LTE: exp.LTE,
     664    }
     665
     666    BITWISE = {
     667        TokenType.AMP: exp.BitwiseAnd,
     668        TokenType.CARET: exp.BitwiseXor,
     669        TokenType.PIPE: exp.BitwiseOr,
     670    }
     671
     672    TERM = {
     673        TokenType.DASH: exp.Sub,
     674        TokenType.PLUS: exp.Add,
     675        TokenType.MOD: exp.Mod,
     676        TokenType.COLLATE: exp.Collate,
     677    }
     678
     679    FACTOR = {
     680        TokenType.DIV: exp.IntDiv,
     681        TokenType.LR_ARROW: exp.Distance,
     682        TokenType.SLASH: exp.Div,
     683        TokenType.STAR: exp.Mul,
     684    }
     685
     686    EXPONENT: t.Dict[TokenType, t.Type[exp.Expression]] = {}
     687
     688    TIMES = {
     689        TokenType.TIME,
     690        TokenType.TIMETZ,
     691    }
     692
     693    TIMESTAMPS = {
     694        TokenType.TIMESTAMP,
     695        TokenType.TIMESTAMPNTZ,
     696        TokenType.TIMESTAMPTZ,
     697        TokenType.TIMESTAMPLTZ,
     698        *TIMES,
     699    }
     700
     701    SET_OPERATIONS = {
     702        TokenType.UNION,
     703        TokenType.INTERSECT,
     704        TokenType.EXCEPT,
     705    }
     706
     707    JOIN_METHODS = {
     708        TokenType.ASOF,
     709        TokenType.NATURAL,
     710        TokenType.POSITIONAL,
     711    }
     712
     713    JOIN_SIDES = {
     714        TokenType.LEFT,
     715        TokenType.RIGHT,
     716        TokenType.FULL,
     717    }
     718
     719    JOIN_KINDS = {
     720        TokenType.ANTI,
     721        TokenType.CROSS,
     722        TokenType.INNER,
     723        TokenType.OUTER,
     724        TokenType.SEMI,
     725        TokenType.STRAIGHT_JOIN,
     726    }
     727
     728    JOIN_HINTS: t.Set[str] = set()
     729
     730    LAMBDAS = {
     731        TokenType.ARROW: lambda self, expressions: self.expression(
     732            exp.Lambda,
     733            this=self._replace_lambda(
     734                self._parse_assignment(),
     735                expressions,
     736            ),
     737            expressions=expressions,
     738        ),
     739        TokenType.FARROW: lambda self, expressions: self.expression(
     740            exp.Kwarg,
     741            this=exp.var(expressions[0].name),
     742            expression=self._parse_assignment(),
     743        ),
     744    }
     745
     746    COLUMN_OPERATORS = {
     747        TokenType.DOT: None,
     748        TokenType.DOTCOLON: lambda self, this, to: self.expression(
     749            exp.JSONCast,
     750            this=this,
     751            to=to,
     752        ),
     753        TokenType.DCOLON: lambda self, this, to: self.expression(
     754            exp.Cast if self.STRICT_CAST else exp.TryCast,
     755            this=this,
     756            to=to,
     757        ),
     758        TokenType.ARROW: lambda self, this, path: self.expression(
     759            exp.JSONExtract,
     760            this=this,
     761            expression=self.dialect.to_json_path(path),
     762            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
     763        ),
     764        TokenType.DARROW: lambda self, this, path: self.expression(
     765            exp.JSONExtractScalar,
     766            this=this,
     767            expression=self.dialect.to_json_path(path),
     768            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
     769        ),
     770        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
     771            exp.JSONBExtract,
     772            this=this,
     773            expression=path,
     774        ),
     775        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
     776            exp.JSONBExtractScalar,
     777            this=this,
     778            expression=path,
     779        ),
     780        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
     781            exp.JSONBContains,
     782            this=this,
     783            expression=key,
     784        ),
     785    }
     786
     787    EXPRESSION_PARSERS = {
     788        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
     789        exp.Column: lambda self: self._parse_column(),
     790        exp.Condition: lambda self: self._parse_assignment(),
     791        exp.DataType: lambda self: self._parse_types(allow_identifiers=False, schema=True),
     792        exp.Expression: lambda self: self._parse_expression(),
     793        exp.From: lambda self: self._parse_from(joins=True),
     794        exp.Group: lambda self: self._parse_group(),
     795        exp.Having: lambda self: self._parse_having(),
     796        exp.Hint: lambda self: self._parse_hint_body(),
     797        exp.Identifier: lambda self: self._parse_id_var(),
     798        exp.Join: lambda self: self._parse_join(),
     799        exp.Lambda: lambda self: self._parse_lambda(),
     800        exp.Lateral: lambda self: self._parse_lateral(),
     801        exp.Limit: lambda self: self._parse_limit(),
     802        exp.Offset: lambda self: self._parse_offset(),
     803        exp.Order: lambda self: self._parse_order(),
     804        exp.Ordered: lambda self: self._parse_ordered(),
     805        exp.Properties: lambda self: self._parse_properties(),
     806        exp.PartitionedByProperty: lambda self: self._parse_partitioned_by(),
     807        exp.Qualify: lambda self: self._parse_qualify(),
     808        exp.Returning: lambda self: self._parse_returning(),
     809        exp.Select: lambda self: self._parse_select(),
     810        exp.Sort: lambda self: self._parse_sort(exp.Sort, TokenType.SORT_BY),
     811        exp.Table: lambda self: self._parse_table_parts(),
     812        exp.TableAlias: lambda self: self._parse_table_alias(),
     813        exp.Tuple: lambda self: self._parse_value(values=False),
     814        exp.Whens: lambda self: self._parse_when_matched(),
     815        exp.Where: lambda self: self._parse_where(),
     816        exp.Window: lambda self: self._parse_named_window(),
     817        exp.With: lambda self: self._parse_with(),
     818        "JOIN_TYPE": lambda self: self._parse_join_parts(),
     819    }
     820
     821    STATEMENT_PARSERS = {
     822        TokenType.ALTER: lambda self: self._parse_alter(),
     823        TokenType.ANALYZE: lambda self: self._parse_analyze(),
     824        TokenType.BEGIN: lambda self: self._parse_transaction(),
     825        TokenType.CACHE: lambda self: self._parse_cache(),
     826        TokenType.COMMENT: lambda self: self._parse_comment(),
     827        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
     828        TokenType.COPY: lambda self: self._parse_copy(),
     829        TokenType.CREATE: lambda self: self._parse_create(),
     830        TokenType.DELETE: lambda self: self._parse_delete(),
     831        TokenType.DESC: lambda self: self._parse_describe(),
     832        TokenType.DESCRIBE: lambda self: self._parse_describe(),
     833        TokenType.DROP: lambda self: self._parse_drop(),
     834        TokenType.GRANT: lambda self: self._parse_grant(),
     835        TokenType.INSERT: lambda self: self._parse_insert(),
     836        TokenType.KILL: lambda self: self._parse_kill(),
     837        TokenType.LOAD: lambda self: self._parse_load(),
     838        TokenType.MERGE: lambda self: self._parse_merge(),
     839        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
     840        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
     841        TokenType.REFRESH: lambda self: self._parse_refresh(),
     842        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
     843        TokenType.SET: lambda self: self._parse_set(),
     844        TokenType.TRUNCATE: lambda self: self._parse_truncate_table(),
     845        TokenType.UNCACHE: lambda self: self._parse_uncache(),
     846        TokenType.UNPIVOT: lambda self: self._parse_simplified_pivot(is_unpivot=True),
     847        TokenType.UPDATE: lambda self: self._parse_update(),
     848        TokenType.USE: lambda self: self._parse_use(),
     849        TokenType.SEMICOLON: lambda self: exp.Semicolon(),
     850    }
     851
     852    UNARY_PARSERS = {
     853        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
     854        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
     855        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
     856        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
     857        TokenType.PIPE_SLASH: lambda self: self.expression(exp.Sqrt, this=self._parse_unary()),
     858        TokenType.DPIPE_SLASH: lambda self: self.expression(exp.Cbrt, this=self._parse_unary()),
     859    }
     860
     861    STRING_PARSERS = {
     862        TokenType.HEREDOC_STRING: lambda self, token: self.expression(
     863            exp.RawString, this=token.text
     864        ),
     865        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
     866            exp.National, this=token.text
     867        ),
     868        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
     869        TokenType.STRING: lambda self, token: self.expression(
     870            exp.Literal, this=token.text, is_string=True
     871        ),
     872        TokenType.UNICODE_STRING: lambda self, token: self.expression(
     873            exp.UnicodeString,
     874            this=token.text,
     875            escape=self._match_text_seq("UESCAPE") and self._parse_string(),
     876        ),
     877    }
     878
     879    NUMERIC_PARSERS = {
     880        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
     881        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
     882        TokenType.HEX_STRING: lambda self, token: self.expression(
     883            exp.HexString,
     884            this=token.text,
     885            is_integer=self.dialect.HEX_STRING_IS_INTEGER_TYPE or None,
     886        ),
     887        TokenType.NUMBER: lambda self, token: self.expression(
     888            exp.Literal, this=token.text, is_string=False
     889        ),
     890    }
     891
     892    PRIMARY_PARSERS = {
     893        **STRING_PARSERS,
     894        **NUMERIC_PARSERS,
     895        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
     896        TokenType.NULL: lambda self, _: self.expression(exp.Null),
     897        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
     898        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
     899        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
     900        TokenType.STAR: lambda self, _: self._parse_star_ops(),
     901    }
     902
     903    PLACEHOLDER_PARSERS = {
     904        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
     905        TokenType.PARAMETER: lambda self: self._parse_parameter(),
     906        TokenType.COLON: lambda self: (
     907            self.expression(exp.Placeholder, this=self._prev.text)
     908            if self._match_set(self.COLON_PLACEHOLDER_TOKENS)
     909            else None
     910        ),
     911    }
     912
     913    RANGE_PARSERS = {
     914        TokenType.AT_GT: binary_range_parser(exp.ArrayContainsAll),
     915        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
     916        TokenType.GLOB: binary_range_parser(exp.Glob),
     917        TokenType.ILIKE: binary_range_parser(exp.ILike),
     918        TokenType.IN: lambda self, this: self._parse_in(this),
     919        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
     920        TokenType.IS: lambda self, this: self._parse_is(this),
     921        TokenType.LIKE: binary_range_parser(exp.Like),
     922        TokenType.LT_AT: binary_range_parser(exp.ArrayContainsAll, reverse_args=True),
     923        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
     924        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
     925        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
     926        TokenType.FOR: lambda self, this: self._parse_comprehension(this),
     927    }
     928
     929    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
     930        "ALLOWED_VALUES": lambda self: self.expression(
     931            exp.AllowedValuesProperty, expressions=self._parse_csv(self._parse_primary)
     932        ),
     933        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
     934        "AUTO": lambda self: self._parse_auto_property(),
     935        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
     936        "BACKUP": lambda self: self.expression(
     937            exp.BackupProperty, this=self._parse_var(any_token=True)
     938        ),
     939        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
     940        "CHARSET": lambda self, **kwargs: self._parse_character_set(**kwargs),
     941        "CHARACTER SET": lambda self, **kwargs: self._parse_character_set(**kwargs),
     942        "CHECKSUM": lambda self: self._parse_checksum(),
     943        "CLUSTER BY": lambda self: self._parse_cluster(),
     944        "CLUSTERED": lambda self: self._parse_clustered_by(),
     945        "COLLATE": lambda self, **kwargs: self._parse_property_assignment(
     946            exp.CollateProperty, **kwargs
     947        ),
     948        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
     949        "CONTAINS": lambda self: self._parse_contains_property(),
     950        "COPY": lambda self: self._parse_copy_property(),
     951        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
     952        "DATA_DELETION": lambda self: self._parse_data_deletion_property(),
     953        "DEFINER": lambda self: self._parse_definer(),
     954        "DETERMINISTIC": lambda self: self.expression(
     955            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
     956        ),
     957        "DISTRIBUTED": lambda self: self._parse_distributed_property(),
     958        "DUPLICATE": lambda self: self._parse_composite_key_property(exp.DuplicateKeyProperty),
     959        "DYNAMIC": lambda self: self.expression(exp.DynamicProperty),
     960        "DISTKEY": lambda self: self._parse_distkey(),
     961        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
     962        "EMPTY": lambda self: self.expression(exp.EmptyProperty),
     963        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
     964        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
     965        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
     966        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
     967        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
     968        "FREESPACE": lambda self: self._parse_freespace(),
     969        "GLOBAL": lambda self: self.expression(exp.GlobalProperty),
     970        "HEAP": lambda self: self.expression(exp.HeapProperty),
     971        "ICEBERG": lambda self: self.expression(exp.IcebergProperty),
     972        "IMMUTABLE": lambda self: self.expression(
     973            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
     974        ),
     975        "INHERITS": lambda self: self.expression(
     976            exp.InheritsProperty, expressions=self._parse_wrapped_csv(self._parse_table)
     977        ),
     978        "INPUT": lambda self: self.expression(exp.InputModelProperty, this=self._parse_schema()),
     979        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
     980        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
     981        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
     982        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
     983        "LIKE": lambda self: self._parse_create_like(),
     984        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
     985        "LOCK": lambda self: self._parse_locking(),
     986        "LOCKING": lambda self: self._parse_locking(),
     987        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
     988        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
     989        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
     990        "MODIFIES": lambda self: self._parse_modifies_property(),
     991        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
     992        "NO": lambda self: self._parse_no_property(),
     993        "ON": lambda self: self._parse_on_property(),
     994        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
     995        "OUTPUT": lambda self: self.expression(exp.OutputModelProperty, this=self._parse_schema()),
     996        "PARTITION": lambda self: self._parse_partitioned_of(),
     997        "PARTITION BY": lambda self: self._parse_partitioned_by(),
     998        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
     999        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
    1000        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
    1001        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
    1002        "READS": lambda self: self._parse_reads_property(),
    1003        "REMOTE": lambda self: self._parse_remote_with_connection(),
    1004        "RETURNS": lambda self: self._parse_returns(),
    1005        "STRICT": lambda self: self.expression(exp.StrictProperty),
    1006        "STREAMING": lambda self: self.expression(exp.StreamingTableProperty),
    1007        "ROW": lambda self: self._parse_row(),
    1008        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
    1009        "SAMPLE": lambda self: self.expression(
    1010            exp.SampleProperty, this=self._match_text_seq("BY") and self._parse_bitwise()
    1011        ),
    1012        "SECURE": lambda self: self.expression(exp.SecureProperty),
    1013        "SECURITY": lambda self: self._parse_security(),
    1014        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
    1015        "SETTINGS": lambda self: self._parse_settings_property(),
    1016        "SHARING": lambda self: self._parse_property_assignment(exp.SharingProperty),
    1017        "SORTKEY": lambda self: self._parse_sortkey(),
    1018        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
    1019        "STABLE": lambda self: self.expression(
    1020            exp.StabilityProperty, this=exp.Literal.string("STABLE")
    1021        ),
    1022        "STORED": lambda self: self._parse_stored(),
    1023        "SYSTEM_VERSIONING": lambda self: self._parse_system_versioning_property(),
    1024        "TBLPROPERTIES": lambda self: self._parse_wrapped_properties(),
    1025        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
    1026        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
    1027        "TO": lambda self: self._parse_to_table(),
    1028        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
    1029        "TRANSFORM": lambda self: self.expression(
    1030            exp.TransformModelProperty, expressions=self._parse_wrapped_csv(self._parse_expression)
    1031        ),
    1032        "TTL": lambda self: self._parse_ttl(),
    1033        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
    1034        "UNLOGGED": lambda self: self.expression(exp.UnloggedProperty),
    1035        "VOLATILE": lambda self: self._parse_volatile_property(),
    1036        "WITH": lambda self: self._parse_with_property(),
    1037    }
    1038
    1039    CONSTRAINT_PARSERS = {
    1040        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
    1041        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
    1042        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
    1043        "CHARACTER SET": lambda self: self.expression(
    1044            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
    1045        ),
    1046        "CHECK": lambda self: self.expression(
    1047            exp.CheckColumnConstraint,
    1048            this=self._parse_wrapped(self._parse_assignment),
    1049            enforced=self._match_text_seq("ENFORCED"),
    1050        ),
    1051        "COLLATE": lambda self: self.expression(
    1052            exp.CollateColumnConstraint,
    1053            this=self._parse_identifier() or self._parse_column(),
    1054        ),
    1055        "COMMENT": lambda self: self.expression(
    1056            exp.CommentColumnConstraint, this=self._parse_string()
    1057        ),
    1058        "COMPRESS": lambda self: self._parse_compress(),
    1059        "CLUSTERED": lambda self: self.expression(
    1060            exp.ClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
    1061        ),
    1062        "NONCLUSTERED": lambda self: self.expression(
    1063            exp.NonClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
    1064        ),
    1065        "DEFAULT": lambda self: self.expression(
    1066            exp.DefaultColumnConstraint, this=self._parse_bitwise()
    1067        ),
    1068        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
    1069        "EPHEMERAL": lambda self: self.expression(
    1070            exp.EphemeralColumnConstraint, this=self._parse_bitwise()
    1071        ),
    1072        "EXCLUDE": lambda self: self.expression(
    1073            exp.ExcludeColumnConstraint, this=self._parse_index_params()
    1074        ),
    1075        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
    1076        "FORMAT": lambda self: self.expression(
    1077            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
    1078        ),
    1079        "GENERATED": lambda self: self._parse_generated_as_identity(),
    1080        "IDENTITY": lambda self: self._parse_auto_increment(),
    1081        "INLINE": lambda self: self._parse_inline(),
    1082        "LIKE": lambda self: self._parse_create_like(),
    1083        "NOT": lambda self: self._parse_not_constraint(),
    1084        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
    1085        "ON": lambda self: (
    1086            self._match(TokenType.UPDATE)
    1087            and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function())
    1088        )
    1089        or self.expression(exp.OnProperty, this=self._parse_id_var()),
    1090        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
    1091        "PERIOD": lambda self: self._parse_period_for_system_time(),
    1092        "PRIMARY KEY": lambda self: self._parse_primary_key(),
    1093        "REFERENCES": lambda self: self._parse_references(match=False),
    1094        "TITLE": lambda self: self.expression(
    1095            exp.TitleColumnConstraint, this=self._parse_var_or_string()
    1096        ),
    1097        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
    1098        "UNIQUE": lambda self: self._parse_unique(),
    1099        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
    1100        "WATERMARK": lambda self: self.expression(
    1101            exp.WatermarkColumnConstraint,
    1102            this=self._match(TokenType.FOR) and self._parse_column(),
    1103            expression=self._match(TokenType.ALIAS) and self._parse_disjunction(),
    1104        ),
    1105        "WITH": lambda self: self.expression(
    1106            exp.Properties, expressions=self._parse_wrapped_properties()
    1107        ),
    1108        "BUCKET": lambda self: self._parse_partitioned_by_bucket_or_truncate(),
    1109        "TRUNCATE": lambda self: self._parse_partitioned_by_bucket_or_truncate(),
    1110    }
    1111
    1112    def _parse_partitioned_by_bucket_or_truncate(self) -> exp.Expression:
    1113        klass = (
    1114            exp.PartitionedByBucket
    1115            if self._prev.text.upper() == "BUCKET"
    1116            else exp.PartitionByTruncate
    1117        )
    1118
    1119        args = self._parse_wrapped_csv(lambda: self._parse_primary() or self._parse_column())
    1120        this, expression = seq_get(args, 0), seq_get(args, 1)
    1121
    1122        if isinstance(this, exp.Literal):
    1123            # Check for Iceberg partition transforms (bucket / truncate) and ensure their arguments are in the right order
    1124            #  - For Hive, it's `bucket(<num buckets>, <col name>)` or `truncate(<num_chars>, <col_name>)`
    1125            #  - For Trino, it's reversed - `bucket(<col name>, <num buckets>)` or `truncate(<col_name>, <num_chars>)`
    1126            # Both variants are canonicalized in the latter i.e `bucket(<col name>, <num buckets>)`
    1127            #
    1128            # Hive ref: https://docs.aws.amazon.com/athena/latest/ug/querying-iceberg-creating-tables.html#querying-iceberg-partitioning
    1129            # Trino ref: https://docs.aws.amazon.com/athena/latest/ug/create-table-as.html#ctas-table-properties
    1130            this, expression = expression, this
    1131
    1132        return self.expression(klass, this=this, expression=expression)
    1133
    1134    ALTER_PARSERS = {
    1135        "ADD": lambda self: self._parse_alter_table_add(),
    1136        "AS": lambda self: self._parse_select(),
    1137        "ALTER": lambda self: self._parse_alter_table_alter(),
    1138        "CLUSTER BY": lambda self: self._parse_cluster(wrapped=True),
    1139        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
    1140        "DROP": lambda self: self._parse_alter_table_drop(),
    1141        "RENAME": lambda self: self._parse_alter_table_rename(),
    1142        "SET": lambda self: self._parse_alter_table_set(),
    1143        "SWAP": lambda self: self.expression(
    1144            exp.SwapTable, this=self._match(TokenType.WITH) and self._parse_table(schema=True)
    1145        ),
    1146    }
    1147
    1148    ALTER_ALTER_PARSERS = {
    1149        "DISTKEY": lambda self: self._parse_alter_diststyle(),
    1150        "DISTSTYLE": lambda self: self._parse_alter_diststyle(),
    1151        "SORTKEY": lambda self: self._parse_alter_sortkey(),
    1152        "COMPOUND": lambda self: self._parse_alter_sortkey(compound=True),
    1153    }
    1154
    1155    SCHEMA_UNNAMED_CONSTRAINTS = {
    1156        "CHECK",
    1157        "EXCLUDE",
    1158        "FOREIGN KEY",
    1159        "LIKE",
    1160        "PERIOD",
    1161        "PRIMARY KEY",
    1162        "UNIQUE",
    1163        "WATERMARK",
    1164        "BUCKET",
    1165        "TRUNCATE",
    1166    }
    1167
    1168    NO_PAREN_FUNCTION_PARSERS = {
    1169        "ANY": lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
    1170        "CASE": lambda self: self._parse_case(),
    1171        "CONNECT_BY_ROOT": lambda self: self.expression(
    1172            exp.ConnectByRoot, this=self._parse_column()
    1173        ),
    1174        "IF": lambda self: self._parse_if(),
    1175    }
    1176
    1177    INVALID_FUNC_NAME_TOKENS = {
    1178        TokenType.IDENTIFIER,
    1179        TokenType.STRING,
    1180    }
    1181
    1182    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
    1183
    1184    KEY_VALUE_DEFINITIONS = (exp.Alias, exp.EQ, exp.PropertyEQ, exp.Slice)
    1185
    1186    FUNCTION_PARSERS = {
    1187        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
    1188        "CEIL": lambda self: self._parse_ceil_floor(exp.Ceil),
    1189        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
    1190        "DECODE": lambda self: self._parse_decode(),
    1191        "EXTRACT": lambda self: self._parse_extract(),
    1192        "FLOOR": lambda self: self._parse_ceil_floor(exp.Floor),
    1193        "GAP_FILL": lambda self: self._parse_gap_fill(),
    1194        "JSON_OBJECT": lambda self: self._parse_json_object(),
    1195        "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
    1196        "JSON_TABLE": lambda self: self._parse_json_table(),
    1197        "MATCH": lambda self: self._parse_match_against(),
    1198        "NORMALIZE": lambda self: self._parse_normalize(),
    1199        "OPENJSON": lambda self: self._parse_open_json(),
    1200        "OVERLAY": lambda self: self._parse_overlay(),
    1201        "POSITION": lambda self: self._parse_position(),
    1202        "PREDICT": lambda self: self._parse_predict(),
    1203        "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
    1204        "STRING_AGG": lambda self: self._parse_string_agg(),
    1205        "SUBSTRING": lambda self: self._parse_substring(),
    1206        "TRIM": lambda self: self._parse_trim(),
    1207        "TRY_CAST": lambda self: self._parse_cast(False, safe=True),
    1208        "TRY_CONVERT": lambda self: self._parse_convert(False, safe=True),
    1209        "XMLELEMENT": lambda self: self.expression(
    1210            exp.XMLElement,
    1211            this=self._match_text_seq("NAME") and self._parse_id_var(),
    1212            expressions=self._match(TokenType.COMMA) and self._parse_csv(self._parse_expression),
    1213        ),
    1214        "XMLTABLE": lambda self: self._parse_xml_table(),
    1215    }
    1216
    1217    QUERY_MODIFIER_PARSERS = {
    1218        TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
    1219        TokenType.PREWHERE: lambda self: ("prewhere", self._parse_prewhere()),
    1220        TokenType.WHERE: lambda self: ("where", self._parse_where()),
    1221        TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
    1222        TokenType.HAVING: lambda self: ("having", self._parse_having()),
    1223        TokenType.QUALIFY: lambda self: ("qualify", self._parse_qualify()),
    1224        TokenType.WINDOW: lambda self: ("windows", self._parse_window_clause()),
    1225        TokenType.ORDER_BY: lambda self: ("order", self._parse_order()),
    1226        TokenType.LIMIT: lambda self: ("limit", self._parse_limit()),
    1227        TokenType.FETCH: lambda self: ("limit", self._parse_limit()),
    1228        TokenType.OFFSET: lambda self: ("offset", self._parse_offset()),
    1229        TokenType.FOR: lambda self: ("locks", self._parse_locks()),
    1230        TokenType.LOCK: lambda self: ("locks", self._parse_locks()),
    1231        TokenType.TABLE_SAMPLE: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
    1232        TokenType.USING: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
    1233        TokenType.CLUSTER_BY: lambda self: (
    1234            "cluster",
    1235            self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
    1236        ),
    1237        TokenType.DISTRIBUTE_BY: lambda self: (
    1238            "distribute",
    1239            self._parse_sort(exp.Distribute, TokenType.DISTRIBUTE_BY),
    1240        ),
    1241        TokenType.SORT_BY: lambda self: ("sort", self._parse_sort(exp.Sort, TokenType.SORT_BY)),
    1242        TokenType.CONNECT_BY: lambda self: ("connect", self._parse_connect(skip_start_token=True)),
    1243        TokenType.START_WITH: lambda self: ("connect", self._parse_connect()),
    1244    }
    1245
    1246    SET_PARSERS = {
    1247        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
    1248        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
    1249        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
    1250        "TRANSACTION": lambda self: self._parse_set_transaction(),
    1251    }
    1252
    1253    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
    1254
    1255    TYPE_LITERAL_PARSERS = {
    1256        exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
    1257    }
    1258
    1259    TYPE_CONVERTERS: t.Dict[exp.DataType.Type, t.Callable[[exp.DataType], exp.DataType]] = {}
    1260
    1261    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
    1262
    1263    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
    1264
    1265    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
    1266    TRANSACTION_CHARACTERISTICS: OPTIONS_TYPE = {
    1267        "ISOLATION": (
    1268            ("LEVEL", "REPEATABLE", "READ"),
    1269            ("LEVEL", "READ", "COMMITTED"),
    1270            ("LEVEL", "READ", "UNCOMITTED"),
    1271            ("LEVEL", "SERIALIZABLE"),
    1272        ),
    1273        "READ": ("WRITE", "ONLY"),
    1274    }
    1275
    1276    CONFLICT_ACTIONS: OPTIONS_TYPE = dict.fromkeys(
    1277        ("ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK", "UPDATE"), tuple()
    1278    )
    1279    CONFLICT_ACTIONS["DO"] = ("NOTHING", "UPDATE")
    1280
    1281    CREATE_SEQUENCE: OPTIONS_TYPE = {
    1282        "SCALE": ("EXTEND", "NOEXTEND"),
    1283        "SHARD": ("EXTEND", "NOEXTEND"),
    1284        "NO": ("CYCLE", "CACHE", "MAXVALUE", "MINVALUE"),
    1285        **dict.fromkeys(
    1286            (
    1287                "SESSION",
    1288                "GLOBAL",
    1289                "KEEP",
    1290                "NOKEEP",
    1291                "ORDER",
    1292                "NOORDER",
    1293                "NOCACHE",
    1294                "CYCLE",
    1295                "NOCYCLE",
    1296                "NOMINVALUE",
    1297                "NOMAXVALUE",
    1298                "NOSCALE",
    1299                "NOSHARD",
    1300            ),
    1301            tuple(),
    1302        ),
    1303    }
    1304
    1305    ISOLATED_LOADING_OPTIONS: OPTIONS_TYPE = {"FOR": ("ALL", "INSERT", "NONE")}
    1306
    1307    USABLES: OPTIONS_TYPE = dict.fromkeys(
    1308        ("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA", "CATALOG"), tuple()
    1309    )
    1310
    1311    CAST_ACTIONS: OPTIONS_TYPE = dict.fromkeys(("RENAME", "ADD"), ("FIELDS",))
    1312
    1313    SCHEMA_BINDING_OPTIONS: OPTIONS_TYPE = {
    1314        "TYPE": ("EVOLUTION",),
    1315        **dict.fromkeys(("BINDING", "COMPENSATION", "EVOLUTION"), tuple()),
    1316    }
    1317
    1318    PROCEDURE_OPTIONS: OPTIONS_TYPE = {}
    1319
    1320    EXECUTE_AS_OPTIONS: OPTIONS_TYPE = dict.fromkeys(("CALLER", "SELF", "OWNER"), tuple())
    1321
    1322    KEY_CONSTRAINT_OPTIONS: OPTIONS_TYPE = {
    1323        "NOT": ("ENFORCED",),
    1324        "MATCH": (
    1325            "FULL",
    1326            "PARTIAL",
    1327            "SIMPLE",
    1328        ),
    1329        "INITIALLY": ("DEFERRED", "IMMEDIATE"),
    1330        "USING": (
    1331            "BTREE",
    1332            "HASH",
    1333        ),
    1334        **dict.fromkeys(("DEFERRABLE", "NORELY", "RELY"), tuple()),
    1335    }
    1336
    1337    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
    1338
    1339    CLONE_KEYWORDS = {"CLONE", "COPY"}
    1340    HISTORICAL_DATA_PREFIX = {"AT", "BEFORE", "END"}
    1341    HISTORICAL_DATA_KIND = {"TIMESTAMP", "OFFSET", "STATEMENT", "STREAM"}
    1342
    1343    OPCLASS_FOLLOW_KEYWORDS = {"ASC", "DESC", "NULLS", "WITH"}
    1344
    1345    OPTYPE_FOLLOW_TOKENS = {TokenType.COMMA, TokenType.R_PAREN}
    1346
    1347    TABLE_INDEX_HINT_TOKENS = {TokenType.FORCE, TokenType.IGNORE, TokenType.USE}
    1348
    1349    VIEW_ATTRIBUTES = {"ENCRYPTION", "SCHEMABINDING", "VIEW_METADATA"}
    1350
    1351    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
    1352    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
    1353    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
    1354
    1355    JSON_KEY_VALUE_SEPARATOR_TOKENS = {TokenType.COLON, TokenType.COMMA, TokenType.IS}
    1356
    1357    FETCH_TOKENS = ID_VAR_TOKENS - {TokenType.ROW, TokenType.ROWS, TokenType.PERCENT}
    1358
    1359    ADD_CONSTRAINT_TOKENS = {
    1360        TokenType.CONSTRAINT,
    1361        TokenType.FOREIGN_KEY,
    1362        TokenType.INDEX,
    1363        TokenType.KEY,
    1364        TokenType.PRIMARY_KEY,
    1365        TokenType.UNIQUE,
    1366    }
    1367
    1368    DISTINCT_TOKENS = {TokenType.DISTINCT}
    1369
    1370    NULL_TOKENS = {TokenType.NULL}
    1371
    1372    UNNEST_OFFSET_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - SET_OPERATIONS
    1373
    1374    SELECT_START_TOKENS = {TokenType.L_PAREN, TokenType.WITH, TokenType.SELECT}
    1375
    1376    COPY_INTO_VARLEN_OPTIONS = {"FILE_FORMAT", "COPY_OPTIONS", "FORMAT_OPTIONS", "CREDENTIAL"}
    1377
    1378    IS_JSON_PREDICATE_KIND = {"VALUE", "SCALAR", "ARRAY", "OBJECT"}
    1379
    1380    ODBC_DATETIME_LITERALS = {
    1381        "d": exp.Date,
    1382        "t": exp.Time,
    1383        "ts": exp.Timestamp,
    1384    }
    1385
    1386    ON_CONDITION_TOKENS = {"ERROR", "NULL", "TRUE", "FALSE", "EMPTY"}
    1387
    1388    PRIVILEGE_FOLLOW_TOKENS = {TokenType.ON, TokenType.COMMA, TokenType.L_PAREN}
    1389
    1390    # The style options for the DESCRIBE statement
    1391    DESCRIBE_STYLES = {"ANALYZE", "EXTENDED", "FORMATTED", "HISTORY"}
    1392
    1393    # The style options for the ANALYZE statement
    1394    ANALYZE_STYLES = {
    1395        "BUFFER_USAGE_LIMIT",
    1396        "FULL",
    1397        "LOCAL",
    1398        "NO_WRITE_TO_BINLOG",
    1399        "SAMPLE",
    1400        "SKIP_LOCKED",
    1401        "VERBOSE",
    1402    }
    1403
    1404    ANALYZE_EXPRESSION_PARSERS = {
    1405        "ALL": lambda self: self._parse_analyze_columns(),
    1406        "COMPUTE": lambda self: self._parse_analyze_statistics(),
    1407        "DELETE": lambda self: self._parse_analyze_delete(),
    1408        "DROP": lambda self: self._parse_analyze_histogram(),
    1409        "ESTIMATE": lambda self: self._parse_analyze_statistics(),
    1410        "LIST": lambda self: self._parse_analyze_list(),
    1411        "PREDICATE": lambda self: self._parse_analyze_columns(),
    1412        "UPDATE": lambda self: self._parse_analyze_histogram(),
    1413        "VALIDATE": lambda self: self._parse_analyze_validate(),
    1414    }
    1415
    1416    PARTITION_KEYWORDS = {"PARTITION", "SUBPARTITION"}
    1417
    1418    AMBIGUOUS_ALIAS_TOKENS = (TokenType.LIMIT, TokenType.OFFSET)
    1419
    1420    OPERATION_MODIFIERS: t.Set[str] = set()
    1421
    1422    RECURSIVE_CTE_SEARCH_KIND = {"BREADTH", "DEPTH", "CYCLE"}
    1423
    1424    MODIFIABLES = (exp.Query, exp.Table, exp.TableFromRows)
    1425
    1426    STRICT_CAST = True
    1427
    1428    PREFIXED_PIVOT_COLUMNS = False
    1429    IDENTIFY_PIVOT_STRINGS = False
    1430
    1431    LOG_DEFAULTS_TO_LN = False
    1432
    1433    # Whether ADD is present for each column added by ALTER TABLE
    1434    ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
    1435
    1436    # Whether the table sample clause expects CSV syntax
    1437    TABLESAMPLE_CSV = False
    1438
    1439    # The default method used for table sampling
    1440    DEFAULT_SAMPLING_METHOD: t.Optional[str] = None
    1441
    1442    # Whether the SET command needs a delimiter (e.g. "=") for assignments
    1443    SET_REQUIRES_ASSIGNMENT_DELIMITER = True
    1444
    1445    # Whether the TRIM function expects the characters to trim as its first argument
    1446    TRIM_PATTERN_FIRST = False
    1447
    1448    # Whether string aliases are supported `SELECT COUNT(*) 'count'`
    1449    STRING_ALIASES = False
    1450
    1451    # Whether query modifiers such as LIMIT are attached to the UNION node (vs its right operand)
    1452    MODIFIERS_ATTACHED_TO_SET_OP = True
    1453    SET_OP_MODIFIERS = {"order", "limit", "offset"}
    1454
    1455    # Whether to parse IF statements that aren't followed by a left parenthesis as commands
    1456    NO_PAREN_IF_COMMANDS = True
    1457
    1458    # Whether the -> and ->> operators expect documents of type JSON (e.g. Postgres)
    1459    JSON_ARROWS_REQUIRE_JSON_TYPE = False
    1460
    1461    # Whether the `:` operator is used to extract a value from a VARIANT column
    1462    COLON_IS_VARIANT_EXTRACT = False
    1463
    1464    # Whether or not a VALUES keyword needs to be followed by '(' to form a VALUES clause.
    1465    # If this is True and '(' is not found, the keyword will be treated as an identifier
    1466    VALUES_FOLLOWED_BY_PAREN = True
    1467
    1468    # Whether implicit unnesting is supported, e.g. SELECT 1 FROM y.z AS z, z.a (Redshift)
    1469    SUPPORTS_IMPLICIT_UNNEST = False
    1470
    1471    # Whether or not interval spans are supported, INTERVAL 1 YEAR TO MONTHS
    1472    INTERVAL_SPANS = True
    1473
    1474    # Whether a PARTITION clause can follow a table reference
    1475    SUPPORTS_PARTITION_SELECTION = False
    1476
    1477    # Whether the `name AS expr` schema/column constraint requires parentheses around `expr`
    1478    WRAPPED_TRANSFORM_COLUMN_CONSTRAINT = True
    1479
    1480    # Whether the 'AS' keyword is optional in the CTE definition syntax
    1481    OPTIONAL_ALIAS_TOKEN_CTE = True
    1482
    1483    __slots__ = (
    1484        "error_level",
    1485        "error_message_context",
    1486        "max_errors",
    1487        "dialect",
    1488        "sql",
    1489        "errors",
    1490        "_tokens",
    1491        "_index",
    1492        "_curr",
    1493        "_next",
    1494        "_prev",
    1495        "_prev_comments",
    1496    )
    1497
    1498    # Autofilled
    1499    SHOW_TRIE: t.Dict = {}
    1500    SET_TRIE: t.Dict = {}
    1501
    1502    def __init__(
    1503        self,
    1504        error_level: t.Optional[ErrorLevel] = None,
    1505        error_message_context: int = 100,
    1506        max_errors: int = 3,
    1507        dialect: DialectType = None,
    1508    ):
    1509        from sqlglot.dialects import Dialect
    1510
    1511        self.error_level = error_level or ErrorLevel.IMMEDIATE
    1512        self.error_message_context = error_message_context
    1513        self.max_errors = max_errors
    1514        self.dialect = Dialect.get_or_raise(dialect)
    1515        self.reset()
    1516
    1517    def reset(self):
    1518        self.sql = ""
    1519        self.errors = []
    1520        self._tokens = []
    1521        self._index = 0
    1522        self._curr = None
    1523        self._next = None
    1524        self._prev = None
    1525        self._prev_comments = None
    1526
    1527    def parse(
    1528        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    1529    ) -> t.List[t.Optional[exp.Expression]]:
    1530        """
    1531        Parses a list of tokens and returns a list of syntax trees, one tree
    1532        per parsed SQL statement.
    1533
    1534        Args:
    1535            raw_tokens: The list of tokens.
    1536            sql: The original SQL string, used to produce helpful debug messages.
    1537
    1538        Returns:
    1539            The list of the produced syntax trees.
    1540        """
    1541        return self._parse(
    1542            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    1543        )
    1544
    1545    def parse_into(
    1546        self,
    1547        expression_types: exp.IntoType,
    1548        raw_tokens: t.List[Token],
    1549        sql: t.Optional[str] = None,
    1550    ) -> t.List[t.Optional[exp.Expression]]:
    1551        """
    1552        Parses a list of tokens into a given Expression type. If a collection of Expression
    1553        types is given instead, this method will try to parse the token list into each one
    1554        of them, stopping at the first for which the parsing succeeds.
    1555
    1556        Args:
    1557            expression_types: The expression type(s) to try and parse the token list into.
    1558            raw_tokens: The list of tokens.
    1559            sql: The original SQL string, used to produce helpful debug messages.
    1560
    1561        Returns:
    1562            The target Expression.
    1563        """
    1564        errors = []
    1565        for expression_type in ensure_list(expression_types):
    1566            parser = self.EXPRESSION_PARSERS.get(expression_type)
    1567            if not parser:
    1568                raise TypeError(f"No parser registered for {expression_type}")
    1569
    1570            try:
    1571                return self._parse(parser, raw_tokens, sql)
    1572            except ParseError as e:
    1573                e.errors[0]["into_expression"] = expression_type
    1574                errors.append(e)
    1575
    1576        raise ParseError(
    1577            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    1578            errors=merge_errors(errors),
    1579        ) from errors[-1]
    1580
    1581    def _parse(
    1582        self,
    1583        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
    1584        raw_tokens: t.List[Token],
    1585        sql: t.Optional[str] = None,
    1586    ) -> t.List[t.Optional[exp.Expression]]:
    1587        self.reset()
    1588        self.sql = sql or ""
    1589
    1590        total = len(raw_tokens)
    1591        chunks: t.List[t.List[Token]] = [[]]
    1592
    1593        for i, token in enumerate(raw_tokens):
    1594            if token.token_type == TokenType.SEMICOLON:
    1595                if token.comments:
    1596                    chunks.append([token])
    1597
    1598                if i < total - 1:
    1599                    chunks.append([])
    1600            else:
    1601                chunks[-1].append(token)
    1602
    1603        expressions = []
    1604
    1605        for tokens in chunks:
    1606            self._index = -1
    1607            self._tokens = tokens
    1608            self._advance()
    1609
    1610            expressions.append(parse_method(self))
    1611
    1612            if self._index < len(self._tokens):
    1613                self.raise_error("Invalid expression / Unexpected token")
    1614
    1615            self.check_errors()
    1616
    1617        return expressions
    1618
    1619    def check_errors(self) -> None:
    1620        """Logs or raises any found errors, depending on the chosen error level setting."""
    1621        if self.error_level == ErrorLevel.WARN:
    1622            for error in self.errors:
    1623                logger.error(str(error))
    1624        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1625            raise ParseError(
    1626                concat_messages(self.errors, self.max_errors),
    1627                errors=merge_errors(self.errors),
    1628            )
    1629
    1630    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1631        """
    1632        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1633        error level setting.
    1634        """
    1635        token = token or self._curr or self._prev or Token.string("")
    1636        start = token.start
    1637        end = token.end + 1
    1638        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1639        highlight = self.sql[start:end]
    1640        end_context = self.sql[end : end + self.error_message_context]
    1641
    1642        error = ParseError.new(
    1643            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1644            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1645            description=message,
    1646            line=token.line,
    1647            col=token.col,
    1648            start_context=start_context,
    1649            highlight=highlight,
    1650            end_context=end_context,
    1651        )
    1652
    1653        if self.error_level == ErrorLevel.IMMEDIATE:
    1654            raise error
    1655
    1656        self.errors.append(error)
    1657
    1658    def expression(
    1659        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1660    ) -> E:
    1661        """
    1662        Creates a new, validated Expression.
    1663
    1664        Args:
    1665            exp_class: The expression class to instantiate.
    1666            comments: An optional list of comments to attach to the expression.
    1667            kwargs: The arguments to set for the expression along with their respective values.
    1668
    1669        Returns:
    1670            The target expression.
    1671        """
    1672        instance = exp_class(**kwargs)
    1673        instance.add_comments(comments) if comments else self._add_comments(instance)
    1674        return self.validate_expression(instance)
    1675
    1676    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
    1677        if expression and self._prev_comments:
    1678            expression.add_comments(self._prev_comments)
    1679            self._prev_comments = None
    1680
    1681    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1682        """
    1683        Validates an Expression, making sure that all its mandatory arguments are set.
    1684
    1685        Args:
    1686            expression: The expression to validate.
    1687            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1688
    1689        Returns:
    1690            The validated expression.
    1691        """
    1692        if self.error_level != ErrorLevel.IGNORE:
    1693            for error_message in expression.error_messages(args):
    1694                self.raise_error(error_message)
    1695
    1696        return expression
    1697
    1698    def _find_sql(self, start: Token, end: Token) -> str:
    1699        return self.sql[start.start : end.end + 1]
    1700
    1701    def _is_connected(self) -> bool:
    1702        return self._prev and self._curr and self._prev.end + 1 == self._curr.start
    1703
    1704    def _advance(self, times: int = 1) -> None:
    1705        self._index += times
    1706        self._curr = seq_get(self._tokens, self._index)
    1707        self._next = seq_get(self._tokens, self._index + 1)
    1708
    1709        if self._index > 0:
    1710            self._prev = self._tokens[self._index - 1]
    1711            self._prev_comments = self._prev.comments
    1712        else:
    1713            self._prev = None
    1714            self._prev_comments = None
    1715
    1716    def _retreat(self, index: int) -> None:
    1717        if index != self._index:
    1718            self._advance(index - self._index)
    1719
    1720    def _warn_unsupported(self) -> None:
    1721        if len(self._tokens) <= 1:
    1722            return
    1723
    1724        # We use _find_sql because self.sql may comprise multiple chunks, and we're only
    1725        # interested in emitting a warning for the one being currently processed.
    1726        sql = self._find_sql(self._tokens[0], self._tokens[-1])[: self.error_message_context]
    1727
    1728        logger.warning(
    1729            f"'{sql}' contains unsupported syntax. Falling back to parsing as a 'Command'."
    1730        )
    1731
    1732    def _parse_command(self) -> exp.Command:
    1733        self._warn_unsupported()
    1734        return self.expression(
    1735            exp.Command,
    1736            comments=self._prev_comments,
    1737            this=self._prev.text.upper(),
    1738            expression=self._parse_string(),
    1739        )
    1740
    1741    def _try_parse(self, parse_method: t.Callable[[], T], retreat: bool = False) -> t.Optional[T]:
    1742        """
    1743        Attemps to backtrack if a parse function that contains a try/catch internally raises an error.
    1744        This behavior can be different depending on the uset-set ErrorLevel, so _try_parse aims to
    1745        solve this by setting & resetting the parser state accordingly
    1746        """
    1747        index = self._index
    1748        error_level = self.error_level
    1749
    1750        self.error_level = ErrorLevel.IMMEDIATE
    1751        try:
    1752            this = parse_method()
    1753        except ParseError:
    1754            this = None
    1755        finally:
    1756            if not this or retreat:
    1757                self._retreat(index)
    1758            self.error_level = error_level
    1759
    1760        return this
    1761
    1762    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
    1763        start = self._prev
    1764        exists = self._parse_exists() if allow_exists else None
    1765
    1766        self._match(TokenType.ON)
    1767
    1768        materialized = self._match_text_seq("MATERIALIZED")
    1769        kind = self._match_set(self.CREATABLES) and self._prev
    1770        if not kind:
    1771            return self._parse_as_command(start)
    1772
    1773        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
    1774            this = self._parse_user_defined_function(kind=kind.token_type)
    1775        elif kind.token_type == TokenType.TABLE:
    1776            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
    1777        elif kind.token_type == TokenType.COLUMN:
    1778            this = self._parse_column()
    1779        else:
    1780            this = self._parse_id_var()
    1781
    1782        self._match(TokenType.IS)
    1783
    1784        return self.expression(
    1785            exp.Comment,
    1786            this=this,
    1787            kind=kind.text,
    1788            expression=self._parse_string(),
    1789            exists=exists,
    1790            materialized=materialized,
    1791        )
    1792
    1793    def _parse_to_table(
    1794        self,
    1795    ) -> exp.ToTableProperty:
    1796        table = self._parse_table_parts(schema=True)
    1797        return self.expression(exp.ToTableProperty, this=table)
    1798
    1799    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
    1800    def _parse_ttl(self) -> exp.Expression:
    1801        def _parse_ttl_action() -> t.Optional[exp.Expression]:
    1802            this = self._parse_bitwise()
    1803
    1804            if self._match_text_seq("DELETE"):
    1805                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
    1806            if self._match_text_seq("RECOMPRESS"):
    1807                return self.expression(
    1808                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
    1809                )
    1810            if self._match_text_seq("TO", "DISK"):
    1811                return self.expression(
    1812                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
    1813                )
    1814            if self._match_text_seq("TO", "VOLUME"):
    1815                return self.expression(
    1816                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
    1817                )
    1818
    1819            return this
    1820
    1821        expressions = self._parse_csv(_parse_ttl_action)
    1822        where = self._parse_where()
    1823        group = self._parse_group()
    1824
    1825        aggregates = None
    1826        if group and self._match(TokenType.SET):
    1827            aggregates = self._parse_csv(self._parse_set_item)
    1828
    1829        return self.expression(
    1830            exp.MergeTreeTTL,
    1831            expressions=expressions,
    1832            where=where,
    1833            group=group,
    1834            aggregates=aggregates,
    1835        )
    1836
    1837    def _parse_statement(self) -> t.Optional[exp.Expression]:
    1838        if self._curr is None:
    1839            return None
    1840
    1841        if self._match_set(self.STATEMENT_PARSERS):
    1842            comments = self._prev_comments
    1843            stmt = self.STATEMENT_PARSERS[self._prev.token_type](self)
    1844            stmt.add_comments(comments, prepend=True)
    1845            return stmt
    1846
    1847        if self._match_set(self.dialect.tokenizer.COMMANDS):
    1848            return self._parse_command()
    1849
    1850        expression = self._parse_expression()
    1851        expression = self._parse_set_operations(expression) if expression else self._parse_select()
    1852        return self._parse_query_modifiers(expression)
    1853
    1854    def _parse_drop(self, exists: bool = False) -> exp.Drop | exp.Command:
    1855        start = self._prev
    1856        temporary = self._match(TokenType.TEMPORARY)
    1857        materialized = self._match_text_seq("MATERIALIZED")
    1858
    1859        kind = self._match_set(self.CREATABLES) and self._prev.text.upper()
    1860        if not kind:
    1861            return self._parse_as_command(start)
    1862
    1863        concurrently = self._match_text_seq("CONCURRENTLY")
    1864        if_exists = exists or self._parse_exists()
    1865
    1866        if kind == "COLUMN":
    1867            this = self._parse_column()
    1868        else:
    1869            this = self._parse_table_parts(
    1870                schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
    1871            )
    1872
    1873        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
    1874
    1875        if self._match(TokenType.L_PAREN, advance=False):
    1876            expressions = self._parse_wrapped_csv(self._parse_types)
    1877        else:
    1878            expressions = None
    1879
    1880        return self.expression(
    1881            exp.Drop,
    1882            exists=if_exists,
    1883            this=this,
    1884            expressions=expressions,
    1885            kind=self.dialect.CREATABLE_KIND_MAPPING.get(kind) or kind,
    1886            temporary=temporary,
    1887            materialized=materialized,
    1888            cascade=self._match_text_seq("CASCADE"),
    1889            constraints=self._match_text_seq("CONSTRAINTS"),
    1890            purge=self._match_text_seq("PURGE"),
    1891            cluster=cluster,
    1892            concurrently=concurrently,
    1893        )
    1894
    1895    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
    1896        return (
    1897            self._match_text_seq("IF")
    1898            and (not not_ or self._match(TokenType.NOT))
    1899            and self._match(TokenType.EXISTS)
    1900        )
    1901
    1902    def _parse_create(self) -> exp.Create | exp.Command:
    1903        # Note: this can't be None because we've matched a statement parser
    1904        start = self._prev
    1905
    1906        replace = (
    1907            start.token_type == TokenType.REPLACE
    1908            or self._match_pair(TokenType.OR, TokenType.REPLACE)
    1909            or self._match_pair(TokenType.OR, TokenType.ALTER)
    1910        )
    1911        refresh = self._match_pair(TokenType.OR, TokenType.REFRESH)
    1912
    1913        unique = self._match(TokenType.UNIQUE)
    1914
    1915        if self._match_text_seq("CLUSTERED", "COLUMNSTORE"):
    1916            clustered = True
    1917        elif self._match_text_seq("NONCLUSTERED", "COLUMNSTORE") or self._match_text_seq(
    1918            "COLUMNSTORE"
    1919        ):
    1920            clustered = False
    1921        else:
    1922            clustered = None
    1923
    1924        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
    1925            self._advance()
    1926
    1927        properties = None
    1928        create_token = self._match_set(self.CREATABLES) and self._prev
    1929
    1930        if not create_token:
    1931            # exp.Properties.Location.POST_CREATE
    1932            properties = self._parse_properties()
    1933            create_token = self._match_set(self.CREATABLES) and self._prev
    1934
    1935            if not properties or not create_token:
    1936                return self._parse_as_command(start)
    1937
    1938        concurrently = self._match_text_seq("CONCURRENTLY")
    1939        exists = self._parse_exists(not_=True)
    1940        this = None
    1941        expression: t.Optional[exp.Expression] = None
    1942        indexes = None
    1943        no_schema_binding = None
    1944        begin = None
    1945        end = None
    1946        clone = None
    1947
    1948        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
    1949            nonlocal properties
    1950            if properties and temp_props:
    1951                properties.expressions.extend(temp_props.expressions)
    1952            elif temp_props:
    1953                properties = temp_props
    1954
    1955        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
    1956            this = self._parse_user_defined_function(kind=create_token.token_type)
    1957
    1958            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
    1959            extend_props(self._parse_properties())
    1960
    1961            expression = self._match(TokenType.ALIAS) and self._parse_heredoc()
    1962            extend_props(self._parse_properties())
    1963
    1964            if not expression:
    1965                if self._match(TokenType.COMMAND):
    1966                    expression = self._parse_as_command(self._prev)
    1967                else:
    1968                    begin = self._match(TokenType.BEGIN)
    1969                    return_ = self._match_text_seq("RETURN")
    1970
    1971                    if self._match(TokenType.STRING, advance=False):
    1972                        # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
    1973                        # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
    1974                        expression = self._parse_string()
    1975                        extend_props(self._parse_properties())
    1976                    else:
    1977                        expression = self._parse_user_defined_function_expression()
    1978
    1979                    end = self._match_text_seq("END")
    1980
    1981                    if return_:
    1982                        expression = self.expression(exp.Return, this=expression)
    1983        elif create_token.token_type == TokenType.INDEX:
    1984            # Postgres allows anonymous indexes, eg. CREATE INDEX IF NOT EXISTS ON t(c)
    1985            if not self._match(TokenType.ON):
    1986                index = self._parse_id_var()
    1987                anonymous = False
    1988            else:
    1989                index = None
    1990                anonymous = True
    1991
    1992            this = self._parse_index(index=index, anonymous=anonymous)
    1993        elif create_token.token_type in self.DB_CREATABLES:
    1994            table_parts = self._parse_table_parts(
    1995                schema=True, is_db_reference=create_token.token_type == TokenType.SCHEMA
    1996            )
    1997
    1998            # exp.Properties.Location.POST_NAME
    1999            self._match(TokenType.COMMA)
    2000            extend_props(self._parse_properties(before=True))
    2001
    2002            this = self._parse_schema(this=table_parts)
    2003
    2004            # exp.Properties.Location.POST_SCHEMA and POST_WITH
    2005            extend_props(self._parse_properties())
    2006
    2007            has_alias = self._match(TokenType.ALIAS)
    2008            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
    2009                # exp.Properties.Location.POST_ALIAS
    2010                extend_props(self._parse_properties())
    2011
    2012            if create_token.token_type == TokenType.SEQUENCE:
    2013                expression = self._parse_types()
    2014                extend_props(self._parse_properties())
    2015            else:
    2016                expression = self._parse_ddl_select()
    2017
    2018                # Some dialects also support using a table as an alias instead of a SELECT.
    2019                # Here we fallback to this as an alternative.
    2020                if not expression and has_alias:
    2021                    expression = self._try_parse(self._parse_table_parts)
    2022
    2023            if create_token.token_type == TokenType.TABLE:
    2024                # exp.Properties.Location.POST_EXPRESSION
    2025                extend_props(self._parse_properties())
    2026
    2027                indexes = []
    2028                while True:
    2029                    index = self._parse_index()
    2030
    2031                    # exp.Properties.Location.POST_INDEX
    2032                    extend_props(self._parse_properties())
    2033                    if not index:
    2034                        break
    2035                    else:
    2036                        self._match(TokenType.COMMA)
    2037                        indexes.append(index)
    2038            elif create_token.token_type == TokenType.VIEW:
    2039                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
    2040                    no_schema_binding = True
    2041            elif create_token.token_type in (TokenType.SINK, TokenType.SOURCE):
    2042                extend_props(self._parse_properties())
    2043
    2044            shallow = self._match_text_seq("SHALLOW")
    2045
    2046            if self._match_texts(self.CLONE_KEYWORDS):
    2047                copy = self._prev.text.lower() == "copy"
    2048                clone = self.expression(
    2049                    exp.Clone, this=self._parse_table(schema=True), shallow=shallow, copy=copy
    2050                )
    2051
    2052        if self._curr and not self._match_set((TokenType.R_PAREN, TokenType.COMMA), advance=False):
    2053            return self._parse_as_command(start)
    2054
    2055        create_kind_text = create_token.text.upper()
    2056        return self.expression(
    2057            exp.Create,
    2058            this=this,
    2059            kind=self.dialect.CREATABLE_KIND_MAPPING.get(create_kind_text) or create_kind_text,
    2060            replace=replace,
    2061            refresh=refresh,
    2062            unique=unique,
    2063            expression=expression,
    2064            exists=exists,
    2065            properties=properties,
    2066            indexes=indexes,
    2067            no_schema_binding=no_schema_binding,
    2068            begin=begin,
    2069            end=end,
    2070            clone=clone,
    2071            concurrently=concurrently,
    2072            clustered=clustered,
    2073        )
    2074
    2075    def _parse_sequence_properties(self) -> t.Optional[exp.SequenceProperties]:
    2076        seq = exp.SequenceProperties()
    2077
    2078        options = []
    2079        index = self._index
    2080
    2081        while self._curr:
    2082            self._match(TokenType.COMMA)
    2083            if self._match_text_seq("INCREMENT"):
    2084                self._match_text_seq("BY")
    2085                self._match_text_seq("=")
    2086                seq.set("increment", self._parse_term())
    2087            elif self._match_text_seq("MINVALUE"):
    2088                seq.set("minvalue", self._parse_term())
    2089            elif self._match_text_seq("MAXVALUE"):
    2090                seq.set("maxvalue", self._parse_term())
    2091            elif self._match(TokenType.START_WITH) or self._match_text_seq("START"):
    2092                self._match_text_seq("=")
    2093                seq.set("start", self._parse_term())
    2094            elif self._match_text_seq("CACHE"):
    2095                # T-SQL allows empty CACHE which is initialized dynamically
    2096                seq.set("cache", self._parse_number() or True)
    2097            elif self._match_text_seq("OWNED", "BY"):
    2098                # "OWNED BY NONE" is the default
    2099                seq.set("owned", None if self._match_text_seq("NONE") else self._parse_column())
    2100            else:
    2101                opt = self._parse_var_from_options(self.CREATE_SEQUENCE, raise_unmatched=False)
    2102                if opt:
    2103                    options.append(opt)
    2104                else:
    2105                    break
    2106
    2107        seq.set("options", options if options else None)
    2108        return None if self._index == index else seq
    2109
    2110    def _parse_property_before(self) -> t.Optional[exp.Expression]:
    2111        # only used for teradata currently
    2112        self._match(TokenType.COMMA)
    2113
    2114        kwargs = {
    2115            "no": self._match_text_seq("NO"),
    2116            "dual": self._match_text_seq("DUAL"),
    2117            "before": self._match_text_seq("BEFORE"),
    2118            "default": self._match_text_seq("DEFAULT"),
    2119            "local": (self._match_text_seq("LOCAL") and "LOCAL")
    2120            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
    2121            "after": self._match_text_seq("AFTER"),
    2122            "minimum": self._match_texts(("MIN", "MINIMUM")),
    2123            "maximum": self._match_texts(("MAX", "MAXIMUM")),
    2124        }
    2125
    2126        if self._match_texts(self.PROPERTY_PARSERS):
    2127            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
    2128            try:
    2129                return parser(self, **{k: v for k, v in kwargs.items() if v})
    2130            except TypeError:
    2131                self.raise_error(f"Cannot parse property '{self._prev.text}'")
    2132
    2133        return None
    2134
    2135    def _parse_wrapped_properties(self) -> t.List[exp.Expression]:
    2136        return self._parse_wrapped_csv(self._parse_property)
    2137
    2138    def _parse_property(self) -> t.Optional[exp.Expression]:
    2139        if self._match_texts(self.PROPERTY_PARSERS):
    2140            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
    2141
    2142        if self._match(TokenType.DEFAULT) and self._match_texts(self.PROPERTY_PARSERS):
    2143            return self.PROPERTY_PARSERS[self._prev.text.upper()](self, default=True)
    2144
    2145        if self._match_text_seq("COMPOUND", "SORTKEY"):
    2146            return self._parse_sortkey(compound=True)
    2147
    2148        if self._match_text_seq("SQL", "SECURITY"):
    2149            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
    2150
    2151        index = self._index
    2152        key = self._parse_column()
    2153
    2154        if not self._match(TokenType.EQ):
    2155            self._retreat(index)
    2156            return self._parse_sequence_properties()
    2157
    2158        # Transform the key to exp.Dot if it's dotted identifiers wrapped in exp.Column or to exp.Var otherwise
    2159        if isinstance(key, exp.Column):
    2160            key = key.to_dot() if len(key.parts) > 1 else exp.var(key.name)
    2161
    2162        value = self._parse_bitwise() or self._parse_var(any_token=True)
    2163
    2164        # Transform the value to exp.Var if it was parsed as exp.Column(exp.Identifier())
    2165        if isinstance(value, exp.Column):
    2166            value = exp.var(value.name)
    2167
    2168        return self.expression(exp.Property, this=key, value=value)
    2169
    2170    def _parse_stored(self) -> t.Union[exp.FileFormatProperty, exp.StorageHandlerProperty]:
    2171        if self._match_text_seq("BY"):
    2172            return self.expression(exp.StorageHandlerProperty, this=self._parse_var_or_string())
    2173
    2174        self._match(TokenType.ALIAS)
    2175        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
    2176        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
    2177
    2178        return self.expression(
    2179            exp.FileFormatProperty,
    2180            this=(
    2181                self.expression(
    2182                    exp.InputOutputFormat,
    2183                    input_format=input_format,
    2184                    output_format=output_format,
    2185                )
    2186                if input_format or output_format
    2187                else self._parse_var_or_string() or self._parse_number() or self._parse_id_var()
    2188            ),
    2189        )
    2190
    2191    def _parse_unquoted_field(self) -> t.Optional[exp.Expression]:
    2192        field = self._parse_field()
    2193        if isinstance(field, exp.Identifier) and not field.quoted:
    2194            field = exp.var(field)
    2195
    2196        return field
    2197
    2198    def _parse_property_assignment(self, exp_class: t.Type[E], **kwargs: t.Any) -> E:
    2199        self._match(TokenType.EQ)
    2200        self._match(TokenType.ALIAS)
    2201
    2202        return self.expression(exp_class, this=self._parse_unquoted_field(), **kwargs)
    2203
    2204    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
    2205        properties = []
    2206        while True:
    2207            if before:
    2208                prop = self._parse_property_before()
    2209            else:
    2210                prop = self._parse_property()
    2211            if not prop:
    2212                break
    2213            for p in ensure_list(prop):
    2214                properties.append(p)
    2215
    2216        if properties:
    2217            return self.expression(exp.Properties, expressions=properties)
    2218
    2219        return None
    2220
    2221    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
    2222        return self.expression(
    2223            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
    2224        )
    2225
    2226    def _parse_security(self) -> t.Optional[exp.SecurityProperty]:
    2227        if self._match_texts(("DEFINER", "INVOKER")):
    2228            security_specifier = self._prev.text.upper()
    2229            return self.expression(exp.SecurityProperty, this=security_specifier)
    2230        return None
    2231
    2232    def _parse_settings_property(self) -> exp.SettingsProperty:
    2233        return self.expression(
    2234            exp.SettingsProperty, expressions=self._parse_csv(self._parse_assignment)
    2235        )
    2236
    2237    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
    2238        if self._index >= 2:
    2239            pre_volatile_token = self._tokens[self._index - 2]
    2240        else:
    2241            pre_volatile_token = None
    2242
    2243        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
    2244            return exp.VolatileProperty()
    2245
    2246        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
    2247
    2248    def _parse_retention_period(self) -> exp.Var:
    2249        # Parse TSQL's HISTORY_RETENTION_PERIOD: {INFINITE | <number> DAY | DAYS | MONTH ...}
    2250        number = self._parse_number()
    2251        number_str = f"{number} " if number else ""
    2252        unit = self._parse_var(any_token=True)
    2253        return exp.var(f"{number_str}{unit}")
    2254
    2255    def _parse_system_versioning_property(
    2256        self, with_: bool = False
    2257    ) -> exp.WithSystemVersioningProperty:
    2258        self._match(TokenType.EQ)
    2259        prop = self.expression(
    2260            exp.WithSystemVersioningProperty,
    2261            **{  # type: ignore
    2262                "on": True,
    2263                "with": with_,
    2264            },
    2265        )
    2266
    2267        if self._match_text_seq("OFF"):
    2268            prop.set("on", False)
    2269            return prop
    2270
    2271        self._match(TokenType.ON)
    2272        if self._match(TokenType.L_PAREN):
    2273            while self._curr and not self._match(TokenType.R_PAREN):
    2274                if self._match_text_seq("HISTORY_TABLE", "="):
    2275                    prop.set("this", self._parse_table_parts())
    2276                elif self._match_text_seq("DATA_CONSISTENCY_CHECK", "="):
    2277                    prop.set("data_consistency", self._advance_any() and self._prev.text.upper())
    2278                elif self._match_text_seq("HISTORY_RETENTION_PERIOD", "="):
    2279                    prop.set("retention_period", self._parse_retention_period())
    2280
    2281                self._match(TokenType.COMMA)
    2282
    2283        return prop
    2284
    2285    def _parse_data_deletion_property(self) -> exp.DataDeletionProperty:
    2286        self._match(TokenType.EQ)
    2287        on = self._match_text_seq("ON") or not self._match_text_seq("OFF")
    2288        prop = self.expression(exp.DataDeletionProperty, on=on)
    2289
    2290        if self._match(TokenType.L_PAREN):
    2291            while self._curr and not self._match(TokenType.R_PAREN):
    2292                if self._match_text_seq("FILTER_COLUMN", "="):
    2293                    prop.set("filter_column", self._parse_column())
    2294                elif self._match_text_seq("RETENTION_PERIOD", "="):
    2295                    prop.set("retention_period", self._parse_retention_period())
    2296
    2297                self._match(TokenType.COMMA)
    2298
    2299        return prop
    2300
    2301    def _parse_distributed_property(self) -> exp.DistributedByProperty:
    2302        kind = "HASH"
    2303        expressions: t.Optional[t.List[exp.Expression]] = None
    2304        if self._match_text_seq("BY", "HASH"):
    2305            expressions = self._parse_wrapped_csv(self._parse_id_var)
    2306        elif self._match_text_seq("BY", "RANDOM"):
    2307            kind = "RANDOM"
    2308
    2309        # If the BUCKETS keyword is not present, the number of buckets is AUTO
    2310        buckets: t.Optional[exp.Expression] = None
    2311        if self._match_text_seq("BUCKETS") and not self._match_text_seq("AUTO"):
    2312            buckets = self._parse_number()
    2313
    2314        return self.expression(
    2315            exp.DistributedByProperty,
    2316            expressions=expressions,
    2317            kind=kind,
    2318            buckets=buckets,
    2319            order=self._parse_order(),
    2320        )
    2321
    2322    def _parse_composite_key_property(self, expr_type: t.Type[E]) -> E:
    2323        self._match_text_seq("KEY")
    2324        expressions = self._parse_wrapped_id_vars()
    2325        return self.expression(expr_type, expressions=expressions)
    2326
    2327    def _parse_with_property(self) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
    2328        if self._match_text_seq("(", "SYSTEM_VERSIONING"):
    2329            prop = self._parse_system_versioning_property(with_=True)
    2330            self._match_r_paren()
    2331            return prop
    2332
    2333        if self._match(TokenType.L_PAREN, advance=False):
    2334            return self._parse_wrapped_properties()
    2335
    2336        if self._match_text_seq("JOURNAL"):
    2337            return self._parse_withjournaltable()
    2338
    2339        if self._match_texts(self.VIEW_ATTRIBUTES):
    2340            return self.expression(exp.ViewAttributeProperty, this=self._prev.text.upper())
    2341
    2342        if self._match_text_seq("DATA"):
    2343            return self._parse_withdata(no=False)
    2344        elif self._match_text_seq("NO", "DATA"):
    2345            return self._parse_withdata(no=True)
    2346
    2347        if self._match(TokenType.SERDE_PROPERTIES, advance=False):
    2348            return self._parse_serde_properties(with_=True)
    2349
    2350        if self._match(TokenType.SCHEMA):
    2351            return self.expression(
    2352                exp.WithSchemaBindingProperty,
    2353                this=self._parse_var_from_options(self.SCHEMA_BINDING_OPTIONS),
    2354            )
    2355
    2356        if self._match_texts(self.PROCEDURE_OPTIONS, advance=False):
    2357            return self.expression(
    2358                exp.WithProcedureOptions, expressions=self._parse_csv(self._parse_procedure_option)
    2359            )
    2360
    2361        if not self._next:
    2362            return None
    2363
    2364        return self._parse_withisolatedloading()
    2365
    2366    def _parse_procedure_option(self) -> exp.Expression | None:
    2367        if self._match_text_seq("EXECUTE", "AS"):
    2368            return self.expression(
    2369                exp.ExecuteAsProperty,
    2370                this=self._parse_var_from_options(self.EXECUTE_AS_OPTIONS, raise_unmatched=False)
    2371                or self._parse_string(),
    2372            )
    2373
    2374        return self._parse_var_from_options(self.PROCEDURE_OPTIONS)
    2375
    2376    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
    2377    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
    2378        self._match(TokenType.EQ)
    2379
    2380        user = self._parse_id_var()
    2381        self._match(TokenType.PARAMETER)
    2382        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
    2383
    2384        if not user or not host:
    2385            return None
    2386
    2387        return exp.DefinerProperty(this=f"{user}@{host}")
    2388
    2389    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
    2390        self._match(TokenType.TABLE)
    2391        self._match(TokenType.EQ)
    2392        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
    2393
    2394    def _parse_log(self, no: bool = False) -> exp.LogProperty:
    2395        return self.expression(exp.LogProperty, no=no)
    2396
    2397    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
    2398        return self.expression(exp.JournalProperty, **kwargs)
    2399
    2400    def _parse_checksum(self) -> exp.ChecksumProperty:
    2401        self._match(TokenType.EQ)
    2402
    2403        on = None
    2404        if self._match(TokenType.ON):
    2405            on = True
    2406        elif self._match_text_seq("OFF"):
    2407            on = False
    2408
    2409        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
    2410
    2411    def _parse_cluster(self, wrapped: bool = False) -> exp.Cluster:
    2412        return self.expression(
    2413            exp.Cluster,
    2414            expressions=(
    2415                self._parse_wrapped_csv(self._parse_ordered)
    2416                if wrapped
    2417                else self._parse_csv(self._parse_ordered)
    2418            ),
    2419        )
    2420
    2421    def _parse_clustered_by(self) -> exp.ClusteredByProperty:
    2422        self._match_text_seq("BY")
    2423
    2424        self._match_l_paren()
    2425        expressions = self._parse_csv(self._parse_column)
    2426        self._match_r_paren()
    2427
    2428        if self._match_text_seq("SORTED", "BY"):
    2429            self._match_l_paren()
    2430            sorted_by = self._parse_csv(self._parse_ordered)
    2431            self._match_r_paren()
    2432        else:
    2433            sorted_by = None
    2434
    2435        self._match(TokenType.INTO)
    2436        buckets = self._parse_number()
    2437        self._match_text_seq("BUCKETS")
    2438
    2439        return self.expression(
    2440            exp.ClusteredByProperty,
    2441            expressions=expressions,
    2442            sorted_by=sorted_by,
    2443            buckets=buckets,
    2444        )
    2445
    2446    def _parse_copy_property(self) -> t.Optional[exp.CopyGrantsProperty]:
    2447        if not self._match_text_seq("GRANTS"):
    2448            self._retreat(self._index - 1)
    2449            return None
    2450
    2451        return self.expression(exp.CopyGrantsProperty)
    2452
    2453    def _parse_freespace(self) -> exp.FreespaceProperty:
    2454        self._match(TokenType.EQ)
    2455        return self.expression(
    2456            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
    2457        )
    2458
    2459    def _parse_mergeblockratio(
    2460        self, no: bool = False, default: bool = False
    2461    ) -> exp.MergeBlockRatioProperty:
    2462        if self._match(TokenType.EQ):
    2463            return self.expression(
    2464                exp.MergeBlockRatioProperty,
    2465                this=self._parse_number(),
    2466                percent=self._match(TokenType.PERCENT),
    2467            )
    2468
    2469        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
    2470
    2471    def _parse_datablocksize(
    2472        self,
    2473        default: t.Optional[bool] = None,
    2474        minimum: t.Optional[bool] = None,
    2475        maximum: t.Optional[bool] = None,
    2476    ) -> exp.DataBlocksizeProperty:
    2477        self._match(TokenType.EQ)
    2478        size = self._parse_number()
    2479
    2480        units = None
    2481        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
    2482            units = self._prev.text
    2483
    2484        return self.expression(
    2485            exp.DataBlocksizeProperty,
    2486            size=size,
    2487            units=units,
    2488            default=default,
    2489            minimum=minimum,
    2490            maximum=maximum,
    2491        )
    2492
    2493    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
    2494        self._match(TokenType.EQ)
    2495        always = self._match_text_seq("ALWAYS")
    2496        manual = self._match_text_seq("MANUAL")
    2497        never = self._match_text_seq("NEVER")
    2498        default = self._match_text_seq("DEFAULT")
    2499
    2500        autotemp = None
    2501        if self._match_text_seq("AUTOTEMP"):
    2502            autotemp = self._parse_schema()
    2503
    2504        return self.expression(
    2505            exp.BlockCompressionProperty,
    2506            always=always,
    2507            manual=manual,
    2508            never=never,
    2509            default=default,
    2510            autotemp=autotemp,
    2511        )
    2512
    2513    def _parse_withisolatedloading(self) -> t.Optional[exp.IsolatedLoadingProperty]:
    2514        index = self._index
    2515        no = self._match_text_seq("NO")
    2516        concurrent = self._match_text_seq("CONCURRENT")
    2517
    2518        if not self._match_text_seq("ISOLATED", "LOADING"):
    2519            self._retreat(index)
    2520            return None
    2521
    2522        target = self._parse_var_from_options(self.ISOLATED_LOADING_OPTIONS, raise_unmatched=False)
    2523        return self.expression(
    2524            exp.IsolatedLoadingProperty, no=no, concurrent=concurrent, target=target
    2525        )
    2526
    2527    def _parse_locking(self) -> exp.LockingProperty:
    2528        if self._match(TokenType.TABLE):
    2529            kind = "TABLE"
    2530        elif self._match(TokenType.VIEW):
    2531            kind = "VIEW"
    2532        elif self._match(TokenType.ROW):
    2533            kind = "ROW"
    2534        elif self._match_text_seq("DATABASE"):
    2535            kind = "DATABASE"
    2536        else:
    2537            kind = None
    2538
    2539        if kind in ("DATABASE", "TABLE", "VIEW"):
    2540            this = self._parse_table_parts()
    2541        else:
    2542            this = None
    2543
    2544        if self._match(TokenType.FOR):
    2545            for_or_in = "FOR"
    2546        elif self._match(TokenType.IN):
    2547            for_or_in = "IN"
    2548        else:
    2549            for_or_in = None
    2550
    2551        if self._match_text_seq("ACCESS"):
    2552            lock_type = "ACCESS"
    2553        elif self._match_texts(("EXCL", "EXCLUSIVE")):
    2554            lock_type = "EXCLUSIVE"
    2555        elif self._match_text_seq("SHARE"):
    2556            lock_type = "SHARE"
    2557        elif self._match_text_seq("READ"):
    2558            lock_type = "READ"
    2559        elif self._match_text_seq("WRITE"):
    2560            lock_type = "WRITE"
    2561        elif self._match_text_seq("CHECKSUM"):
    2562            lock_type = "CHECKSUM"
    2563        else:
    2564            lock_type = None
    2565
    2566        override = self._match_text_seq("OVERRIDE")
    2567
    2568        return self.expression(
    2569            exp.LockingProperty,
    2570            this=this,
    2571            kind=kind,
    2572            for_or_in=for_or_in,
    2573            lock_type=lock_type,
    2574            override=override,
    2575        )
    2576
    2577    def _parse_partition_by(self) -> t.List[exp.Expression]:
    2578        if self._match(TokenType.PARTITION_BY):
    2579            return self._parse_csv(self._parse_assignment)
    2580        return []
    2581
    2582    def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
    2583        def _parse_partition_bound_expr() -> t.Optional[exp.Expression]:
    2584            if self._match_text_seq("MINVALUE"):
    2585                return exp.var("MINVALUE")
    2586            if self._match_text_seq("MAXVALUE"):
    2587                return exp.var("MAXVALUE")
    2588            return self._parse_bitwise()
    2589
    2590        this: t.Optional[exp.Expression | t.List[exp.Expression]] = None
    2591        expression = None
    2592        from_expressions = None
    2593        to_expressions = None
    2594
    2595        if self._match(TokenType.IN):
    2596            this = self._parse_wrapped_csv(self._parse_bitwise)
    2597        elif self._match(TokenType.FROM):
    2598            from_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
    2599            self._match_text_seq("TO")
    2600            to_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
    2601        elif self._match_text_seq("WITH", "(", "MODULUS"):
    2602            this = self._parse_number()
    2603            self._match_text_seq(",", "REMAINDER")
    2604            expression = self._parse_number()
    2605            self._match_r_paren()
    2606        else:
    2607            self.raise_error("Failed to parse partition bound spec.")
    2608
    2609        return self.expression(
    2610            exp.PartitionBoundSpec,
    2611            this=this,
    2612            expression=expression,
    2613            from_expressions=from_expressions,
    2614            to_expressions=to_expressions,
    2615        )
    2616
    2617    # https://www.postgresql.org/docs/current/sql-createtable.html
    2618    def _parse_partitioned_of(self) -> t.Optional[exp.PartitionedOfProperty]:
    2619        if not self._match_text_seq("OF"):
    2620            self._retreat(self._index - 1)
    2621            return None
    2622
    2623        this = self._parse_table(schema=True)
    2624
    2625        if self._match(TokenType.DEFAULT):
    2626            expression: exp.Var | exp.PartitionBoundSpec = exp.var("DEFAULT")
    2627        elif self._match_text_seq("FOR", "VALUES"):
    2628            expression = self._parse_partition_bound_spec()
    2629        else:
    2630            self.raise_error("Expecting either DEFAULT or FOR VALUES clause.")
    2631
    2632        return self.expression(exp.PartitionedOfProperty, this=this, expression=expression)
    2633
    2634    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
    2635        self._match(TokenType.EQ)
    2636        return self.expression(
    2637            exp.PartitionedByProperty,
    2638            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
    2639        )
    2640
    2641    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
    2642        if self._match_text_seq("AND", "STATISTICS"):
    2643            statistics = True
    2644        elif self._match_text_seq("AND", "NO", "STATISTICS"):
    2645            statistics = False
    2646        else:
    2647            statistics = None
    2648
    2649        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
    2650
    2651    def _parse_contains_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
    2652        if self._match_text_seq("SQL"):
    2653            return self.expression(exp.SqlReadWriteProperty, this="CONTAINS SQL")
    2654        return None
    2655
    2656    def _parse_modifies_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
    2657        if self._match_text_seq("SQL", "DATA"):
    2658            return self.expression(exp.SqlReadWriteProperty, this="MODIFIES SQL DATA")
    2659        return None
    2660
    2661    def _parse_no_property(self) -> t.Optional[exp.Expression]:
    2662        if self._match_text_seq("PRIMARY", "INDEX"):
    2663            return exp.NoPrimaryIndexProperty()
    2664        if self._match_text_seq("SQL"):
    2665            return self.expression(exp.SqlReadWriteProperty, this="NO SQL")
    2666        return None
    2667
    2668    def _parse_on_property(self) -> t.Optional[exp.Expression]:
    2669        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
    2670            return exp.OnCommitProperty()
    2671        if self._match_text_seq("COMMIT", "DELETE", "ROWS"):
    2672            return exp.OnCommitProperty(delete=True)
    2673        return self.expression(exp.OnProperty, this=self._parse_schema(self._parse_id_var()))
    2674
    2675    def _parse_reads_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
    2676        if self._match_text_seq("SQL", "DATA"):
    2677            return self.expression(exp.SqlReadWriteProperty, this="READS SQL DATA")
    2678        return None
    2679
    2680    def _parse_distkey(self) -> exp.DistKeyProperty:
    2681        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
    2682
    2683    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
    2684        table = self._parse_table(schema=True)
    2685
    2686        options = []
    2687        while self._match_texts(("INCLUDING", "EXCLUDING")):
    2688            this = self._prev.text.upper()
    2689
    2690            id_var = self._parse_id_var()
    2691            if not id_var:
    2692                return None
    2693
    2694            options.append(
    2695                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
    2696            )
    2697
    2698        return self.expression(exp.LikeProperty, this=table, expressions=options)
    2699
    2700    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
    2701        return self.expression(
    2702            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
    2703        )
    2704
    2705    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
    2706        self._match(TokenType.EQ)
    2707        return self.expression(
    2708            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
    2709        )
    2710
    2711    def _parse_remote_with_connection(self) -> exp.RemoteWithConnectionModelProperty:
    2712        self._match_text_seq("WITH", "CONNECTION")
    2713        return self.expression(
    2714            exp.RemoteWithConnectionModelProperty, this=self._parse_table_parts()
    2715        )
    2716
    2717    def _parse_returns(self) -> exp.ReturnsProperty:
    2718        value: t.Optional[exp.Expression]
    2719        null = None
    2720        is_table = self._match(TokenType.TABLE)
    2721
    2722        if is_table:
    2723            if self._match(TokenType.LT):
    2724                value = self.expression(
    2725                    exp.Schema,
    2726                    this="TABLE",
    2727                    expressions=self._parse_csv(self._parse_struct_types),
    2728                )
    2729                if not self._match(TokenType.GT):
    2730                    self.raise_error("Expecting >")
    2731            else:
    2732                value = self._parse_schema(exp.var("TABLE"))
    2733        elif self._match_text_seq("NULL", "ON", "NULL", "INPUT"):
    2734            null = True
    2735            value = None
    2736        else:
    2737            value = self._parse_types()
    2738
    2739        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table, null=null)
    2740
    2741    def _parse_describe(self) -> exp.Describe:
    2742        kind = self._match_set(self.CREATABLES) and self._prev.text
    2743        style = self._match_texts(self.DESCRIBE_STYLES) and self._prev.text.upper()
    2744        if self._match(TokenType.DOT):
    2745            style = None
    2746            self._retreat(self._index - 2)
    2747
    2748        format = self._parse_property() if self._match(TokenType.FORMAT, advance=False) else None
    2749
    2750        if self._match_set(self.STATEMENT_PARSERS, advance=False):
    2751            this = self._parse_statement()
    2752        else:
    2753            this = self._parse_table(schema=True)
    2754
    2755        properties = self._parse_properties()
    2756        expressions = properties.expressions if properties else None
    2757        partition = self._parse_partition()
    2758        return self.expression(
    2759            exp.Describe,
    2760            this=this,
    2761            style=style,
    2762            kind=kind,
    2763            expressions=expressions,
    2764            partition=partition,
    2765            format=format,
    2766        )
    2767
    2768    def _parse_multitable_inserts(self, comments: t.Optional[t.List[str]]) -> exp.MultitableInserts:
    2769        kind = self._prev.text.upper()
    2770        expressions = []
    2771
    2772        def parse_conditional_insert() -> t.Optional[exp.ConditionalInsert]:
    2773            if self._match(TokenType.WHEN):
    2774                expression = self._parse_disjunction()
    2775                self._match(TokenType.THEN)
    2776            else:
    2777                expression = None
    2778
    2779            else_ = self._match(TokenType.ELSE)
    2780
    2781            if not self._match(TokenType.INTO):
    2782                return None
    2783
    2784            return self.expression(
    2785                exp.ConditionalInsert,
    2786                this=self.expression(
    2787                    exp.Insert,
    2788                    this=self._parse_table(schema=True),
    2789                    expression=self._parse_derived_table_values(),
    2790                ),
    2791                expression=expression,
    2792                else_=else_,
    2793            )
    2794
    2795        expression = parse_conditional_insert()
    2796        while expression is not None:
    2797            expressions.append(expression)
    2798            expression = parse_conditional_insert()
    2799
    2800        return self.expression(
    2801            exp.MultitableInserts,
    2802            kind=kind,
    2803            comments=comments,
    2804            expressions=expressions,
    2805            source=self._parse_table(),
    2806        )
    2807
    2808    def _parse_insert(self) -> t.Union[exp.Insert, exp.MultitableInserts]:
    2809        comments = []
    2810        hint = self._parse_hint()
    2811        overwrite = self._match(TokenType.OVERWRITE)
    2812        ignore = self._match(TokenType.IGNORE)
    2813        local = self._match_text_seq("LOCAL")
    2814        alternative = None
    2815        is_function = None
    2816
    2817        if self._match_text_seq("DIRECTORY"):
    2818            this: t.Optional[exp.Expression] = self.expression(
    2819                exp.Directory,
    2820                this=self._parse_var_or_string(),
    2821                local=local,
    2822                row_format=self._parse_row_format(match_row=True),
    2823            )
    2824        else:
    2825            if self._match_set((TokenType.FIRST, TokenType.ALL)):
    2826                comments += ensure_list(self._prev_comments)
    2827                return self._parse_multitable_inserts(comments)
    2828
    2829            if self._match(TokenType.OR):
    2830                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
    2831
    2832            self._match(TokenType.INTO)
    2833            comments += ensure_list(self._prev_comments)
    2834            self._match(TokenType.TABLE)
    2835            is_function = self._match(TokenType.FUNCTION)
    2836
    2837            this = (
    2838                self._parse_table(schema=True, parse_partition=True)
    2839                if not is_function
    2840                else self._parse_function()
    2841            )
    2842            if isinstance(this, exp.Table) and self._match(TokenType.ALIAS, advance=False):
    2843                this.set("alias", self._parse_table_alias())
    2844
    2845        returning = self._parse_returning()
    2846
    2847        return self.expression(
    2848            exp.Insert,
    2849            comments=comments,
    2850            hint=hint,
    2851            is_function=is_function,
    2852            this=this,
    2853            stored=self._match_text_seq("STORED") and self._parse_stored(),
    2854            by_name=self._match_text_seq("BY", "NAME"),
    2855            exists=self._parse_exists(),
    2856            where=self._match_pair(TokenType.REPLACE, TokenType.WHERE) and self._parse_assignment(),
    2857            partition=self._match(TokenType.PARTITION_BY) and self._parse_partitioned_by(),
    2858            settings=self._match_text_seq("SETTINGS") and self._parse_settings_property(),
    2859            expression=self._parse_derived_table_values() or self._parse_ddl_select(),
    2860            conflict=self._parse_on_conflict(),
    2861            returning=returning or self._parse_returning(),
    2862            overwrite=overwrite,
    2863            alternative=alternative,
    2864            ignore=ignore,
    2865            source=self._match(TokenType.TABLE) and self._parse_table(),
    2866        )
    2867
    2868    def _parse_kill(self) -> exp.Kill:
    2869        kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
    2870
    2871        return self.expression(
    2872            exp.Kill,
    2873            this=self._parse_primary(),
    2874            kind=kind,
    2875        )
    2876
    2877    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
    2878        conflict = self._match_text_seq("ON", "CONFLICT")
    2879        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
    2880
    2881        if not conflict and not duplicate:
    2882            return None
    2883
    2884        conflict_keys = None
    2885        constraint = None
    2886
    2887        if conflict:
    2888            if self._match_text_seq("ON", "CONSTRAINT"):
    2889                constraint = self._parse_id_var()
    2890            elif self._match(TokenType.L_PAREN):
    2891                conflict_keys = self._parse_csv(self._parse_id_var)
    2892                self._match_r_paren()
    2893
    2894        action = self._parse_var_from_options(self.CONFLICT_ACTIONS)
    2895        if self._prev.token_type == TokenType.UPDATE:
    2896            self._match(TokenType.SET)
    2897            expressions = self._parse_csv(self._parse_equality)
    2898        else:
    2899            expressions = None
    2900
    2901        return self.expression(
    2902            exp.OnConflict,
    2903            duplicate=duplicate,
    2904            expressions=expressions,
    2905            action=action,
    2906            conflict_keys=conflict_keys,
    2907            constraint=constraint,
    2908            where=self._parse_where(),
    2909        )
    2910
    2911    def _parse_returning(self) -> t.Optional[exp.Returning]:
    2912        if not self._match(TokenType.RETURNING):
    2913            return None
    2914        return self.expression(
    2915            exp.Returning,
    2916            expressions=self._parse_csv(self._parse_expression),
    2917            into=self._match(TokenType.INTO) and self._parse_table_part(),
    2918        )
    2919
    2920    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
    2921        if not self._match(TokenType.FORMAT):
    2922            return None
    2923        return self._parse_row_format()
    2924
    2925    def _parse_serde_properties(self, with_: bool = False) -> t.Optional[exp.SerdeProperties]:
    2926        index = self._index
    2927        with_ = with_ or self._match_text_seq("WITH")
    2928
    2929        if not self._match(TokenType.SERDE_PROPERTIES):
    2930            self._retreat(index)
    2931            return None
    2932        return self.expression(
    2933            exp.SerdeProperties,
    2934            **{  # type: ignore
    2935                "expressions": self._parse_wrapped_properties(),
    2936                "with": with_,
    2937            },
    2938        )
    2939
    2940    def _parse_row_format(
    2941        self, match_row: bool = False
    2942    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
    2943        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
    2944            return None
    2945
    2946        if self._match_text_seq("SERDE"):
    2947            this = self._parse_string()
    2948
    2949            serde_properties = self._parse_serde_properties()
    2950
    2951            return self.expression(
    2952                exp.RowFormatSerdeProperty, this=this, serde_properties=serde_properties
    2953            )
    2954
    2955        self._match_text_seq("DELIMITED")
    2956
    2957        kwargs = {}
    2958
    2959        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
    2960            kwargs["fields"] = self._parse_string()
    2961            if self._match_text_seq("ESCAPED", "BY"):
    2962                kwargs["escaped"] = self._parse_string()
    2963        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
    2964            kwargs["collection_items"] = self._parse_string()
    2965        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
    2966            kwargs["map_keys"] = self._parse_string()
    2967        if self._match_text_seq("LINES", "TERMINATED", "BY"):
    2968            kwargs["lines"] = self._parse_string()
    2969        if self._match_text_seq("NULL", "DEFINED", "AS"):
    2970            kwargs["null"] = self._parse_string()
    2971
    2972        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
    2973
    2974    def _parse_load(self) -> exp.LoadData | exp.Command:
    2975        if self._match_text_seq("DATA"):
    2976            local = self._match_text_seq("LOCAL")
    2977            self._match_text_seq("INPATH")
    2978            inpath = self._parse_string()
    2979            overwrite = self._match(TokenType.OVERWRITE)
    2980            self._match_pair(TokenType.INTO, TokenType.TABLE)
    2981
    2982            return self.expression(
    2983                exp.LoadData,
    2984                this=self._parse_table(schema=True),
    2985                local=local,
    2986                overwrite=overwrite,
    2987                inpath=inpath,
    2988                partition=self._parse_partition(),
    2989                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
    2990                serde=self._match_text_seq("SERDE") and self._parse_string(),
    2991            )
    2992        return self._parse_as_command(self._prev)
    2993
    2994    def _parse_delete(self) -> exp.Delete:
    2995        # This handles MySQL's "Multiple-Table Syntax"
    2996        # https://dev.mysql.com/doc/refman/8.0/en/delete.html
    2997        tables = None
    2998        if not self._match(TokenType.FROM, advance=False):
    2999            tables = self._parse_csv(self._parse_table) or None
    3000
    3001        returning = self._parse_returning()
    3002
    3003        return self.expression(
    3004            exp.Delete,
    3005            tables=tables,
    3006            this=self._match(TokenType.FROM) and self._parse_table(joins=True),
    3007            using=self._match(TokenType.USING) and self._parse_table(joins=True),
    3008            cluster=self._match(TokenType.ON) and self._parse_on_property(),
    3009            where=self._parse_where(),
    3010            returning=returning or self._parse_returning(),
    3011            limit=self._parse_limit(),
    3012        )
    3013
    3014    def _parse_update(self) -> exp.Update:
    3015        this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
    3016        expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
    3017        returning = self._parse_returning()
    3018        return self.expression(
    3019            exp.Update,
    3020            **{  # type: ignore
    3021                "this": this,
    3022                "expressions": expressions,
    3023                "from": self._parse_from(joins=True),
    3024                "where": self._parse_where(),
    3025                "returning": returning or self._parse_returning(),
    3026                "order": self._parse_order(),
    3027                "limit": self._parse_limit(),
    3028            },
    3029        )
    3030
    3031    def _parse_use(self) -> exp.Use:
    3032        return self.expression(
    3033            exp.Use,
    3034            kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
    3035            this=self._parse_table(schema=False),
    3036        )
    3037
    3038    def _parse_uncache(self) -> exp.Uncache:
    3039        if not self._match(TokenType.TABLE):
    3040            self.raise_error("Expecting TABLE after UNCACHE")
    3041
    3042        return self.expression(
    3043            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
    3044        )
    3045
    3046    def _parse_cache(self) -> exp.Cache:
    3047        lazy = self._match_text_seq("LAZY")
    3048        self._match(TokenType.TABLE)
    3049        table = self._parse_table(schema=True)
    3050
    3051        options = []
    3052        if self._match_text_seq("OPTIONS"):
    3053            self._match_l_paren()
    3054            k = self._parse_string()
    3055            self._match(TokenType.EQ)
    3056            v = self._parse_string()
    3057            options = [k, v]
    3058            self._match_r_paren()
    3059
    3060        self._match(TokenType.ALIAS)
    3061        return self.expression(
    3062            exp.Cache,
    3063            this=table,
    3064            lazy=lazy,
    3065            options=options,
    3066            expression=self._parse_select(nested=True),
    3067        )
    3068
    3069    def _parse_partition(self) -> t.Optional[exp.Partition]:
    3070        if not self._match_texts(self.PARTITION_KEYWORDS):
    3071            return None
    3072
    3073        return self.expression(
    3074            exp.Partition,
    3075            subpartition=self._prev.text.upper() == "SUBPARTITION",
    3076            expressions=self._parse_wrapped_csv(self._parse_assignment),
    3077        )
    3078
    3079    def _parse_value(self, values: bool = True) -> t.Optional[exp.Tuple]:
    3080        def _parse_value_expression() -> t.Optional[exp.Expression]:
    3081            if self.dialect.SUPPORTS_VALUES_DEFAULT and self._match(TokenType.DEFAULT):
    3082                return exp.var(self._prev.text.upper())
    3083            return self._parse_expression()
    3084
    3085        if self._match(TokenType.L_PAREN):
    3086            expressions = self._parse_csv(_parse_value_expression)
    3087            self._match_r_paren()
    3088            return self.expression(exp.Tuple, expressions=expressions)
    3089
    3090        # In some dialects we can have VALUES 1, 2 which results in 1 column & 2 rows.
    3091        expression = self._parse_expression()
    3092        if expression:
    3093            return self.expression(exp.Tuple, expressions=[expression])
    3094        return None
    3095
    3096    def _parse_projections(self) -> t.List[exp.Expression]:
    3097        return self._parse_expressions()
    3098
    3099    def _parse_wrapped_select(self, table: bool = False) -> t.Optional[exp.Expression]:
    3100        if self._match_set((TokenType.PIVOT, TokenType.UNPIVOT)):
    3101            this: t.Optional[exp.Expression] = self._parse_simplified_pivot(
    3102                is_unpivot=self._prev.token_type == TokenType.UNPIVOT
    3103            )
    3104        elif self._match(TokenType.FROM):
    3105            from_ = self._parse_from(skip_from_token=True)
    3106            # Support parentheses for duckdb FROM-first syntax
    3107            select = self._parse_select()
    3108            if select:
    3109                select.set("from", from_)
    3110                this = select
    3111            else:
    3112                this = exp.select("*").from_(t.cast(exp.From, from_))
    3113        else:
    3114            this = (
    3115                self._parse_table()
    3116                if table
    3117                else self._parse_select(nested=True, parse_set_operation=False)
    3118            )
    3119
    3120            # Transform exp.Values into a exp.Table to pass through parse_query_modifiers
    3121            # in case a modifier (e.g. join) is following
    3122            if table and isinstance(this, exp.Values) and this.alias:
    3123                alias = this.args["alias"].pop()
    3124                this = exp.Table(this=this, alias=alias)
    3125
    3126            this = self._parse_query_modifiers(self._parse_set_operations(this))
    3127
    3128        return this
    3129
    3130    def _parse_select(
    3131        self,
    3132        nested: bool = False,
    3133        table: bool = False,
    3134        parse_subquery_alias: bool = True,
    3135        parse_set_operation: bool = True,
    3136    ) -> t.Optional[exp.Expression]:
    3137        cte = self._parse_with()
    3138
    3139        if cte:
    3140            this = self._parse_statement()
    3141
    3142            if not this:
    3143                self.raise_error("Failed to parse any statement following CTE")
    3144                return cte
    3145
    3146            if "with" in this.arg_types:
    3147                this.set("with", cte)
    3148            else:
    3149                self.raise_error(f"{this.key} does not support CTE")
    3150                this = cte
    3151
    3152            return this
    3153
    3154        # duckdb supports leading with FROM x
    3155        from_ = self._parse_from() if self._match(TokenType.FROM, advance=False) else None
    3156
    3157        if self._match(TokenType.SELECT):
    3158            comments = self._prev_comments
    3159
    3160            hint = self._parse_hint()
    3161
    3162            if self._next and not self._next.token_type == TokenType.DOT:
    3163                all_ = self._match(TokenType.ALL)
    3164                distinct = self._match_set(self.DISTINCT_TOKENS)
    3165            else:
    3166                all_, distinct = None, None
    3167
    3168            kind = (
    3169                self._match(TokenType.ALIAS)
    3170                and self._match_texts(("STRUCT", "VALUE"))
    3171                and self._prev.text.upper()
    3172            )
    3173
    3174            if distinct:
    3175                distinct = self.expression(
    3176                    exp.Distinct,
    3177                    on=self._parse_value(values=False) if self._match(TokenType.ON) else None,
    3178                )
    3179
    3180            if all_ and distinct:
    3181                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
    3182
    3183            operation_modifiers = []
    3184            while self._curr and self._match_texts(self.OPERATION_MODIFIERS):
    3185                operation_modifiers.append(exp.var(self._prev.text.upper()))
    3186
    3187            limit = self._parse_limit(top=True)
    3188            projections = self._parse_projections()
    3189
    3190            this = self.expression(
    3191                exp.Select,
    3192                kind=kind,
    3193                hint=hint,
    3194                distinct=distinct,
    3195                expressions=projections,
    3196                limit=limit,
    3197                operation_modifiers=operation_modifiers or None,
    3198            )
    3199            this.comments = comments
    3200
    3201            into = self._parse_into()
    3202            if into:
    3203                this.set("into", into)
    3204
    3205            if not from_:
    3206                from_ = self._parse_from()
    3207
    3208            if from_:
    3209                this.set("from", from_)
    3210
    3211            this = self._parse_query_modifiers(this)
    3212        elif (table or nested) and self._match(TokenType.L_PAREN):
    3213            this = self._parse_wrapped_select(table=table)
    3214
    3215            # We return early here so that the UNION isn't attached to the subquery by the
    3216            # following call to _parse_set_operations, but instead becomes the parent node
    3217            self._match_r_paren()
    3218            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
    3219        elif self._match(TokenType.VALUES, advance=False):
    3220            this = self._parse_derived_table_values()
    3221        elif from_:
    3222            this = exp.select("*").from_(from_.this, copy=False)
    3223        elif self._match(TokenType.SUMMARIZE):
    3224            table = self._match(TokenType.TABLE)
    3225            this = self._parse_select() or self._parse_string() or self._parse_table()
    3226            return self.expression(exp.Summarize, this=this, table=table)
    3227        elif self._match(TokenType.DESCRIBE):
    3228            this = self._parse_describe()
    3229        elif self._match_text_seq("STREAM"):
    3230            this = self._parse_function()
    3231            if this:
    3232                this = self.expression(exp.Stream, this=this)
    3233            else:
    3234                self._retreat(self._index - 1)
    3235        else:
    3236            this = None
    3237
    3238        return self._parse_set_operations(this) if parse_set_operation else this
    3239
    3240    def _parse_recursive_with_search(self) -> t.Optional[exp.RecursiveWithSearch]:
    3241        self._match_text_seq("SEARCH")
    3242
    3243        kind = self._match_texts(self.RECURSIVE_CTE_SEARCH_KIND) and self._prev.text.upper()
    3244
    3245        if not kind:
    3246            return None
    3247
    3248        self._match_text_seq("FIRST", "BY")
    3249
    3250        return self.expression(
    3251            exp.RecursiveWithSearch,
    3252            kind=kind,
    3253            this=self._parse_id_var(),
    3254            expression=self._match_text_seq("SET") and self._parse_id_var(),
    3255            using=self._match_text_seq("USING") and self._parse_id_var(),
    3256        )
    3257
    3258    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
    3259        if not skip_with_token and not self._match(TokenType.WITH):
    3260            return None
    3261
    3262        comments = self._prev_comments
    3263        recursive = self._match(TokenType.RECURSIVE)
    3264
    3265        last_comments = None
    3266        expressions = []
    3267        while True:
    3268            cte = self._parse_cte()
    3269            if isinstance(cte, exp.CTE):
    3270                expressions.append(cte)
    3271                if last_comments:
    3272                    cte.add_comments(last_comments)
    3273
    3274            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
    3275                break
    3276            else:
    3277                self._match(TokenType.WITH)
    3278
    3279            last_comments = self._prev_comments
    3280
    3281        return self.expression(
    3282            exp.With,
    3283            comments=comments,
    3284            expressions=expressions,
    3285            recursive=recursive,
    3286            search=self._parse_recursive_with_search(),
    3287        )
    3288
    3289    def _parse_cte(self) -> t.Optional[exp.CTE]:
    3290        index = self._index
    3291
    3292        alias = self._parse_table_alias(self.ID_VAR_TOKENS)
    3293        if not alias or not alias.this:
    3294            self.raise_error("Expected CTE to have alias")
    3295
    3296        if not self._match(TokenType.ALIAS) and not self.OPTIONAL_ALIAS_TOKEN_CTE:
    3297            self._retreat(index)
    3298            return None
    3299
    3300        comments = self._prev_comments
    3301
    3302        if self._match_text_seq("NOT", "MATERIALIZED"):
    3303            materialized = False
    3304        elif self._match_text_seq("MATERIALIZED"):
    3305            materialized = True
    3306        else:
    3307            materialized = None
    3308
    3309        cte = self.expression(
    3310            exp.CTE,
    3311            this=self._parse_wrapped(self._parse_statement),
    3312            alias=alias,
    3313            materialized=materialized,
    3314            comments=comments,
    3315        )
    3316
    3317        if isinstance(cte.this, exp.Values):
    3318            cte.set("this", exp.select("*").from_(exp.alias_(cte.this, "_values", table=True)))
    3319
    3320        return cte
    3321
    3322    def _parse_table_alias(
    3323        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
    3324    ) -> t.Optional[exp.TableAlias]:
    3325        # In some dialects, LIMIT and OFFSET can act as both identifiers and keywords (clauses)
    3326        # so this section tries to parse the clause version and if it fails, it treats the token
    3327        # as an identifier (alias)
    3328        if self._can_parse_limit_or_offset():
    3329            return None
    3330
    3331        any_token = self._match(TokenType.ALIAS)
    3332        alias = (
    3333            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
    3334            or self._parse_string_as_identifier()
    3335        )
    3336
    3337        index = self._index
    3338        if self._match(TokenType.L_PAREN):
    3339            columns = self._parse_csv(self._parse_function_parameter)
    3340            self._match_r_paren() if columns else self._retreat(index)
    3341        else:
    3342            columns = None
    3343
    3344        if not alias and not columns:
    3345            return None
    3346
    3347        table_alias = self.expression(exp.TableAlias, this=alias, columns=columns)
    3348
    3349        # We bubble up comments from the Identifier to the TableAlias
    3350        if isinstance(alias, exp.Identifier):
    3351            table_alias.add_comments(alias.pop_comments())
    3352
    3353        return table_alias
    3354
    3355    def _parse_subquery(
    3356        self, this: t.Optional[exp.Expression], parse_alias: bool = True
    3357    ) -> t.Optional[exp.Subquery]:
    3358        if not this:
    3359            return None
    3360
    3361        return self.expression(
    3362            exp.Subquery,
    3363            this=this,
    3364            pivots=self._parse_pivots(),
    3365            alias=self._parse_table_alias() if parse_alias else None,
    3366            sample=self._parse_table_sample(),
    3367        )
    3368
    3369    def _implicit_unnests_to_explicit(self, this: E) -> E:
    3370        from sqlglot.optimizer.normalize_identifiers import normalize_identifiers as _norm
    3371
    3372        refs = {_norm(this.args["from"].this.copy(), dialect=self.dialect).alias_or_name}
    3373        for i, join in enumerate(this.args.get("joins") or []):
    3374            table = join.this
    3375            normalized_table = table.copy()
    3376            normalized_table.meta["maybe_column"] = True
    3377            normalized_table = _norm(normalized_table, dialect=self.dialect)
    3378
    3379            if isinstance(table, exp.Table) and not join.args.get("on"):
    3380                if normalized_table.parts[0].name in refs:
    3381                    table_as_column = table.to_column()
    3382                    unnest = exp.Unnest(expressions=[table_as_column])
    3383
    3384                    # Table.to_column creates a parent Alias node that we want to convert to
    3385                    # a TableAlias and attach to the Unnest, so it matches the parser's output
    3386                    if isinstance(table.args.get("alias"), exp.TableAlias):
    3387                        table_as_column.replace(table_as_column.this)
    3388                        exp.alias_(unnest, None, table=[table.args["alias"].this], copy=False)
    3389
    3390                    table.replace(unnest)
    3391
    3392            refs.add(normalized_table.alias_or_name)
    3393
    3394        return this
    3395
    3396    def _parse_query_modifiers(
    3397        self, this: t.Optional[exp.Expression]
    3398    ) -> t.Optional[exp.Expression]:
    3399        if isinstance(this, self.MODIFIABLES):
    3400            for join in self._parse_joins():
    3401                this.append("joins", join)
    3402            for lateral in iter(self._parse_lateral, None):
    3403                this.append("laterals", lateral)
    3404
    3405            while True:
    3406                if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
    3407                    parser = self.QUERY_MODIFIER_PARSERS[self._curr.token_type]
    3408                    key, expression = parser(self)
    3409
    3410                    if expression:
    3411                        this.set(key, expression)
    3412                        if key == "limit":
    3413                            offset = expression.args.pop("offset", None)
    3414
    3415                            if offset:
    3416                                offset = exp.Offset(expression=offset)
    3417                                this.set("offset", offset)
    3418
    3419                                limit_by_expressions = expression.expressions
    3420                                expression.set("expressions", None)
    3421                                offset.set("expressions", limit_by_expressions)
    3422                        continue
    3423                break
    3424
    3425        if self.SUPPORTS_IMPLICIT_UNNEST and this and this.args.get("from"):
    3426            this = self._implicit_unnests_to_explicit(this)
    3427
    3428        return this
    3429
    3430    def _parse_hint_fallback_to_string(self) -> t.Optional[exp.Hint]:
    3431        start = self._curr
    3432        while self._curr:
    3433            self._advance()
    3434
    3435        end = self._tokens[self._index - 1]
    3436        return exp.Hint(expressions=[self._find_sql(start, end)])
    3437
    3438    def _parse_hint_function_call(self) -> t.Optional[exp.Expression]:
    3439        return self._parse_function_call()
    3440
    3441    def _parse_hint_body(self) -> t.Optional[exp.Hint]:
    3442        start_index = self._index
    3443        should_fallback_to_string = False
    3444
    3445        hints = []
    3446        try:
    3447            for hint in iter(
    3448                lambda: self._parse_csv(
    3449                    lambda: self._parse_hint_function_call() or self._parse_var(upper=True),
    3450                ),
    3451                [],
    3452            ):
    3453                hints.extend(hint)
    3454        except ParseError:
    3455            should_fallback_to_string = True
    3456
    3457        if should_fallback_to_string or self._curr:
    3458            self._retreat(start_index)
    3459            return self._parse_hint_fallback_to_string()
    3460
    3461        return self.expression(exp.Hint, expressions=hints)
    3462
    3463    def _parse_hint(self) -> t.Optional[exp.Hint]:
    3464        if self._match(TokenType.HINT) and self._prev_comments:
    3465            return exp.maybe_parse(self._prev_comments[0], into=exp.Hint, dialect=self.dialect)
    3466
    3467        return None
    3468
    3469    def _parse_into(self) -> t.Optional[exp.Into]:
    3470        if not self._match(TokenType.INTO):
    3471            return None
    3472
    3473        temp = self._match(TokenType.TEMPORARY)
    3474        unlogged = self._match_text_seq("UNLOGGED")
    3475        self._match(TokenType.TABLE)
    3476
    3477        return self.expression(
    3478            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
    3479        )
    3480
    3481    def _parse_from(
    3482        self, joins: bool = False, skip_from_token: bool = False
    3483    ) -> t.Optional[exp.From]:
    3484        if not skip_from_token and not self._match(TokenType.FROM):
    3485            return None
    3486
    3487        return self.expression(
    3488            exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
    3489        )
    3490
    3491    def _parse_match_recognize_measure(self) -> exp.MatchRecognizeMeasure:
    3492        return self.expression(
    3493            exp.MatchRecognizeMeasure,
    3494            window_frame=self._match_texts(("FINAL", "RUNNING")) and self._prev.text.upper(),
    3495            this=self._parse_expression(),
    3496        )
    3497
    3498    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
    3499        if not self._match(TokenType.MATCH_RECOGNIZE):
    3500            return None
    3501
    3502        self._match_l_paren()
    3503
    3504        partition = self._parse_partition_by()
    3505        order = self._parse_order()
    3506
    3507        measures = (
    3508            self._parse_csv(self._parse_match_recognize_measure)
    3509            if self._match_text_seq("MEASURES")
    3510            else None
    3511        )
    3512
    3513        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
    3514            rows = exp.var("ONE ROW PER MATCH")
    3515        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
    3516            text = "ALL ROWS PER MATCH"
    3517            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
    3518                text += " SHOW EMPTY MATCHES"
    3519            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
    3520                text += " OMIT EMPTY MATCHES"
    3521            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
    3522                text += " WITH UNMATCHED ROWS"
    3523            rows = exp.var(text)
    3524        else:
    3525            rows = None
    3526
    3527        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
    3528            text = "AFTER MATCH SKIP"
    3529            if self._match_text_seq("PAST", "LAST", "ROW"):
    3530                text += " PAST LAST ROW"
    3531            elif self._match_text_seq("TO", "NEXT", "ROW"):
    3532                text += " TO NEXT ROW"
    3533            elif self._match_text_seq("TO", "FIRST"):
    3534                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
    3535            elif self._match_text_seq("TO", "LAST"):
    3536                text += f" TO LAST {self._advance_any().text}"  # type: ignore
    3537            after = exp.var(text)
    3538        else:
    3539            after = None
    3540
    3541        if self._match_text_seq("PATTERN"):
    3542            self._match_l_paren()
    3543
    3544            if not self._curr:
    3545                self.raise_error("Expecting )", self._curr)
    3546
    3547            paren = 1
    3548            start = self._curr
    3549
    3550            while self._curr and paren > 0:
    3551                if self._curr.token_type == TokenType.L_PAREN:
    3552                    paren += 1
    3553                if self._curr.token_type == TokenType.R_PAREN:
    3554                    paren -= 1
    3555
    3556                end = self._prev
    3557                self._advance()
    3558
    3559            if paren > 0:
    3560                self.raise_error("Expecting )", self._curr)
    3561
    3562            pattern = exp.var(self._find_sql(start, end))
    3563        else:
    3564            pattern = None
    3565
    3566        define = (
    3567            self._parse_csv(self._parse_name_as_expression)
    3568            if self._match_text_seq("DEFINE")
    3569            else None
    3570        )
    3571
    3572        self._match_r_paren()
    3573
    3574        return self.expression(
    3575            exp.MatchRecognize,
    3576            partition_by=partition,
    3577            order=order,
    3578            measures=measures,
    3579            rows=rows,
    3580            after=after,
    3581            pattern=pattern,
    3582            define=define,
    3583            alias=self._parse_table_alias(),
    3584        )
    3585
    3586    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
    3587        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
    3588        if not cross_apply and self._match_pair(TokenType.OUTER, TokenType.APPLY):
    3589            cross_apply = False
    3590
    3591        if cross_apply is not None:
    3592            this = self._parse_select(table=True)
    3593            view = None
    3594            outer = None
    3595        elif self._match(TokenType.LATERAL):
    3596            this = self._parse_select(table=True)
    3597            view = self._match(TokenType.VIEW)
    3598            outer = self._match(TokenType.OUTER)
    3599        else:
    3600            return None
    3601
    3602        if not this:
    3603            this = (
    3604                self._parse_unnest()
    3605                or self._parse_function()
    3606                or self._parse_id_var(any_token=False)
    3607            )
    3608
    3609            while self._match(TokenType.DOT):
    3610                this = exp.Dot(
    3611                    this=this,
    3612                    expression=self._parse_function() or self._parse_id_var(any_token=False),
    3613                )
    3614
    3615        ordinality: t.Optional[bool] = None
    3616
    3617        if view:
    3618            table = self._parse_id_var(any_token=False)
    3619            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
    3620            table_alias: t.Optional[exp.TableAlias] = self.expression(
    3621                exp.TableAlias, this=table, columns=columns
    3622            )
    3623        elif isinstance(this, (exp.Subquery, exp.Unnest)) and this.alias:
    3624            # We move the alias from the lateral's child node to the lateral itself
    3625            table_alias = this.args["alias"].pop()
    3626        else:
    3627            ordinality = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
    3628            table_alias = self._parse_table_alias()
    3629
    3630        return self.expression(
    3631            exp.Lateral,
    3632            this=this,
    3633            view=view,
    3634            outer=outer,
    3635            alias=table_alias,
    3636            cross_apply=cross_apply,
    3637            ordinality=ordinality,
    3638        )
    3639
    3640    def _parse_join_parts(
    3641        self,
    3642    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
    3643        return (
    3644            self._match_set(self.JOIN_METHODS) and self._prev,
    3645            self._match_set(self.JOIN_SIDES) and self._prev,
    3646            self._match_set(self.JOIN_KINDS) and self._prev,
    3647        )
    3648
    3649    def _parse_using_identifiers(self) -> t.List[exp.Expression]:
    3650        def _parse_column_as_identifier() -> t.Optional[exp.Expression]:
    3651            this = self._parse_column()
    3652            if isinstance(this, exp.Column):
    3653                return this.this
    3654            return this
    3655
    3656        return self._parse_wrapped_csv(_parse_column_as_identifier, optional=True)
    3657
    3658    def _parse_join(
    3659        self, skip_join_token: bool = False, parse_bracket: bool = False
    3660    ) -> t.Optional[exp.Join]:
    3661        if self._match(TokenType.COMMA):
    3662            table = self._try_parse(self._parse_table)
    3663            if table:
    3664                return self.expression(exp.Join, this=table)
    3665            return None
    3666
    3667        index = self._index
    3668        method, side, kind = self._parse_join_parts()
    3669        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
    3670        join = self._match(TokenType.JOIN) or (kind and kind.token_type == TokenType.STRAIGHT_JOIN)
    3671
    3672        if not skip_join_token and not join:
    3673            self._retreat(index)
    3674            kind = None
    3675            method = None
    3676            side = None
    3677
    3678        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
    3679        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
    3680
    3681        if not skip_join_token and not join and not outer_apply and not cross_apply:
    3682            return None
    3683
    3684        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table(parse_bracket=parse_bracket)}
    3685        if kind and kind.token_type == TokenType.ARRAY and self._match(TokenType.COMMA):
    3686            kwargs["expressions"] = self._parse_csv(
    3687                lambda: self._parse_table(parse_bracket=parse_bracket)
    3688            )
    3689
    3690        if method:
    3691            kwargs["method"] = method.text
    3692        if side:
    3693            kwargs["side"] = side.text
    3694        if kind:
    3695            kwargs["kind"] = kind.text
    3696        if hint:
    3697            kwargs["hint"] = hint
    3698
    3699        if self._match(TokenType.MATCH_CONDITION):
    3700            kwargs["match_condition"] = self._parse_wrapped(self._parse_comparison)
    3701
    3702        if self._match(TokenType.ON):
    3703            kwargs["on"] = self._parse_assignment()
    3704        elif self._match(TokenType.USING):
    3705            kwargs["using"] = self._parse_using_identifiers()
    3706        elif (
    3707            not (outer_apply or cross_apply)
    3708            and not isinstance(kwargs["this"], exp.Unnest)
    3709            and not (kind and kind.token_type in (TokenType.CROSS, TokenType.ARRAY))
    3710        ):
    3711            index = self._index
    3712            joins: t.Optional[list] = list(self._parse_joins())
    3713
    3714            if joins and self._match(TokenType.ON):
    3715                kwargs["on"] = self._parse_assignment()
    3716            elif joins and self._match(TokenType.USING):
    3717                kwargs["using"] = self._parse_using_identifiers()
    3718            else:
    3719                joins = None
    3720                self._retreat(index)
    3721
    3722            kwargs["this"].set("joins", joins if joins else None)
    3723
    3724        comments = [c for token in (method, side, kind) if token for c in token.comments]
    3725        return self.expression(exp.Join, comments=comments, **kwargs)
    3726
    3727    def _parse_opclass(self) -> t.Optional[exp.Expression]:
    3728        this = self._parse_assignment()
    3729
    3730        if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
    3731            return this
    3732
    3733        if not self._match_set(self.OPTYPE_FOLLOW_TOKENS, advance=False):
    3734            return self.expression(exp.Opclass, this=this, expression=self._parse_table_parts())
    3735
    3736        return this
    3737
    3738    def _parse_index_params(self) -> exp.IndexParameters:
    3739        using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
    3740
    3741        if self._match(TokenType.L_PAREN, advance=False):
    3742            columns = self._parse_wrapped_csv(self._parse_with_operator)
    3743        else:
    3744            columns = None
    3745
    3746        include = self._parse_wrapped_id_vars() if self._match_text_seq("INCLUDE") else None
    3747        partition_by = self._parse_partition_by()
    3748        with_storage = self._match(TokenType.WITH) and self._parse_wrapped_properties()
    3749        tablespace = (
    3750            self._parse_var(any_token=True)
    3751            if self._match_text_seq("USING", "INDEX", "TABLESPACE")
    3752            else None
    3753        )
    3754        where = self._parse_where()
    3755
    3756        on = self._parse_field() if self._match(TokenType.ON) else None
    3757
    3758        return self.expression(
    3759            exp.IndexParameters,
    3760            using=using,
    3761            columns=columns,
    3762            include=include,
    3763            partition_by=partition_by,
    3764            where=where,
    3765            with_storage=with_storage,
    3766            tablespace=tablespace,
    3767            on=on,
    3768        )
    3769
    3770    def _parse_index(
    3771        self, index: t.Optional[exp.Expression] = None, anonymous: bool = False
    3772    ) -> t.Optional[exp.Index]:
    3773        if index or anonymous:
    3774            unique = None
    3775            primary = None
    3776            amp = None
    3777
    3778            self._match(TokenType.ON)
    3779            self._match(TokenType.TABLE)  # hive
    3780            table = self._parse_table_parts(schema=True)
    3781        else:
    3782            unique = self._match(TokenType.UNIQUE)
    3783            primary = self._match_text_seq("PRIMARY")
    3784            amp = self._match_text_seq("AMP")
    3785
    3786            if not self._match(TokenType.INDEX):
    3787                return None
    3788
    3789            index = self._parse_id_var()
    3790            table = None
    3791
    3792        params = self._parse_index_params()
    3793
    3794        return self.expression(
    3795            exp.Index,
    3796            this=index,
    3797            table=table,
    3798            unique=unique,
    3799            primary=primary,
    3800            amp=amp,
    3801            params=params,
    3802        )
    3803
    3804    def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
    3805        hints: t.List[exp.Expression] = []
    3806        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
    3807            # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
    3808            hints.append(
    3809                self.expression(
    3810                    exp.WithTableHint,
    3811                    expressions=self._parse_csv(
    3812                        lambda: self._parse_function() or self._parse_var(any_token=True)
    3813                    ),
    3814                )
    3815            )
    3816            self._match_r_paren()
    3817        else:
    3818            # https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
    3819            while self._match_set(self.TABLE_INDEX_HINT_TOKENS):
    3820                hint = exp.IndexTableHint(this=self._prev.text.upper())
    3821
    3822                self._match_set((TokenType.INDEX, TokenType.KEY))
    3823                if self._match(TokenType.FOR):
    3824                    hint.set("target", self._advance_any() and self._prev.text.upper())
    3825
    3826                hint.set("expressions", self._parse_wrapped_id_vars())
    3827                hints.append(hint)
    3828
    3829        return hints or None
    3830
    3831    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
    3832        return (
    3833            (not schema and self._parse_function(optional_parens=False))
    3834            or self._parse_id_var(any_token=False)
    3835            or self._parse_string_as_identifier()
    3836            or self._parse_placeholder()
    3837        )
    3838
    3839    def _parse_table_parts(
    3840        self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
    3841    ) -> exp.Table:
    3842        catalog = None
    3843        db = None
    3844        table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
    3845
    3846        while self._match(TokenType.DOT):
    3847            if catalog:
    3848                # This allows nesting the table in arbitrarily many dot expressions if needed
    3849                table = self.expression(
    3850                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
    3851                )
    3852            else:
    3853                catalog = db
    3854                db = table
    3855                # "" used for tsql FROM a..b case
    3856                table = self._parse_table_part(schema=schema) or ""
    3857
    3858        if (
    3859            wildcard
    3860            and self._is_connected()
    3861            and (isinstance(table, exp.Identifier) or not table)
    3862            and self._match(TokenType.STAR)
    3863        ):
    3864            if isinstance(table, exp.Identifier):
    3865                table.args["this"] += "*"
    3866            else:
    3867                table = exp.Identifier(this="*")
    3868
    3869        # We bubble up comments from the Identifier to the Table
    3870        comments = table.pop_comments() if isinstance(table, exp.Expression) else None
    3871
    3872        if is_db_reference:
    3873            catalog = db
    3874            db = table
    3875            table = None
    3876
    3877        if not table and not is_db_reference:
    3878            self.raise_error(f"Expected table name but got {self._curr}")
    3879        if not db and is_db_reference:
    3880            self.raise_error(f"Expected database name but got {self._curr}")
    3881
    3882        table = self.expression(
    3883            exp.Table,
    3884            comments=comments,
    3885            this=table,
    3886            db=db,
    3887            catalog=catalog,
    3888        )
    3889
    3890        changes = self._parse_changes()
    3891        if changes:
    3892            table.set("changes", changes)
    3893
    3894        at_before = self._parse_historical_data()
    3895        if at_before:
    3896            table.set("when", at_before)
    3897
    3898        pivots = self._parse_pivots()
    3899        if pivots:
    3900            table.set("pivots", pivots)
    3901
    3902        return table
    3903
    3904    def _parse_table(
    3905        self,
    3906        schema: bool = False,
    3907        joins: bool = False,
    3908        alias_tokens: t.Optional[t.Collection[TokenType]] = None,
    3909        parse_bracket: bool = False,
    3910        is_db_reference: bool = False,
    3911        parse_partition: bool = False,
    3912    ) -> t.Optional[exp.Expression]:
    3913        lateral = self._parse_lateral()
    3914        if lateral:
    3915            return lateral
    3916
    3917        unnest = self._parse_unnest()
    3918        if unnest:
    3919            return unnest
    3920
    3921        values = self._parse_derived_table_values()
    3922        if values:
    3923            return values
    3924
    3925        subquery = self._parse_select(table=True)
    3926        if subquery:
    3927            if not subquery.args.get("pivots"):
    3928                subquery.set("pivots", self._parse_pivots())
    3929            return subquery
    3930
    3931        bracket = parse_bracket and self._parse_bracket(None)
    3932        bracket = self.expression(exp.Table, this=bracket) if bracket else None
    3933
    3934        rows_from = self._match_text_seq("ROWS", "FROM") and self._parse_wrapped_csv(
    3935            self._parse_table
    3936        )
    3937        rows_from = self.expression(exp.Table, rows_from=rows_from) if rows_from else None
    3938
    3939        only = self._match(TokenType.ONLY)
    3940
    3941        this = t.cast(
    3942            exp.Expression,
    3943            bracket
    3944            or rows_from
    3945            or self._parse_bracket(
    3946                self._parse_table_parts(schema=schema, is_db_reference=is_db_reference)
    3947            ),
    3948        )
    3949
    3950        if only:
    3951            this.set("only", only)
    3952
    3953        # Postgres supports a wildcard (table) suffix operator, which is a no-op in this context
    3954        self._match_text_seq("*")
    3955
    3956        parse_partition = parse_partition or self.SUPPORTS_PARTITION_SELECTION
    3957        if parse_partition and self._match(TokenType.PARTITION, advance=False):
    3958            this.set("partition", self._parse_partition())
    3959
    3960        if schema:
    3961            return self._parse_schema(this=this)
    3962
    3963        version = self._parse_version()
    3964
    3965        if version:
    3966            this.set("version", version)
    3967
    3968        if self.dialect.ALIAS_POST_TABLESAMPLE:
    3969            this.set("sample", self._parse_table_sample())
    3970
    3971        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
    3972        if alias:
    3973            this.set("alias", alias)
    3974
    3975        if isinstance(this, exp.Table) and self._match_text_seq("AT"):
    3976            return self.expression(
    3977                exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
    3978            )
    3979
    3980        this.set("hints", self._parse_table_hints())
    3981
    3982        if not this.args.get("pivots"):
    3983            this.set("pivots", self._parse_pivots())
    3984
    3985        if not self.dialect.ALIAS_POST_TABLESAMPLE:
    3986            this.set("sample", self._parse_table_sample())
    3987
    3988        if joins:
    3989            for join in self._parse_joins():
    3990                this.append("joins", join)
    3991
    3992        if self._match_pair(TokenType.WITH, TokenType.ORDINALITY):
    3993            this.set("ordinality", True)
    3994            this.set("alias", self._parse_table_alias())
    3995
    3996        return this
    3997
    3998    def _parse_version(self) -> t.Optional[exp.Version]:
    3999        if self._match(TokenType.TIMESTAMP_SNAPSHOT):
    4000            this = "TIMESTAMP"
    4001        elif self._match(TokenType.VERSION_SNAPSHOT):
    4002            this = "VERSION"
    4003        else:
    4004            return None
    4005
    4006        if self._match_set((TokenType.FROM, TokenType.BETWEEN)):
    4007            kind = self._prev.text.upper()
    4008            start = self._parse_bitwise()
    4009            self._match_texts(("TO", "AND"))
    4010            end = self._parse_bitwise()
    4011            expression: t.Optional[exp.Expression] = self.expression(
    4012                exp.Tuple, expressions=[start, end]
    4013            )
    4014        elif self._match_text_seq("CONTAINED", "IN"):
    4015            kind = "CONTAINED IN"
    4016            expression = self.expression(
    4017                exp.Tuple, expressions=self._parse_wrapped_csv(self._parse_bitwise)
    4018            )
    4019        elif self._match(TokenType.ALL):
    4020            kind = "ALL"
    4021            expression = None
    4022        else:
    4023            self._match_text_seq("AS", "OF")
    4024            kind = "AS OF"
    4025            expression = self._parse_type()
    4026
    4027        return self.expression(exp.Version, this=this, expression=expression, kind=kind)
    4028
    4029    def _parse_historical_data(self) -> t.Optional[exp.HistoricalData]:
    4030        # https://docs.snowflake.com/en/sql-reference/constructs/at-before
    4031        index = self._index
    4032        historical_data = None
    4033        if self._match_texts(self.HISTORICAL_DATA_PREFIX):
    4034            this = self._prev.text.upper()
    4035            kind = (
    4036                self._match(TokenType.L_PAREN)
    4037                and self._match_texts(self.HISTORICAL_DATA_KIND)
    4038                and self._prev.text.upper()
    4039            )
    4040            expression = self._match(TokenType.FARROW) and self._parse_bitwise()
    4041
    4042            if expression:
    4043                self._match_r_paren()
    4044                historical_data = self.expression(
    4045                    exp.HistoricalData, this=this, kind=kind, expression=expression
    4046                )
    4047            else:
    4048                self._retreat(index)
    4049
    4050        return historical_data
    4051
    4052    def _parse_changes(self) -> t.Optional[exp.Changes]:
    4053        if not self._match_text_seq("CHANGES", "(", "INFORMATION", "=>"):
    4054            return None
    4055
    4056        information = self._parse_var(any_token=True)
    4057        self._match_r_paren()
    4058
    4059        return self.expression(
    4060            exp.Changes,
    4061            information=information,
    4062            at_before=self._parse_historical_data(),
    4063            end=self._parse_historical_data(),
    4064        )
    4065
    4066    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
    4067        if not self._match(TokenType.UNNEST):
    4068            return None
    4069
    4070        expressions = self._parse_wrapped_csv(self._parse_equality)
    4071        offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
    4072
    4073        alias = self._parse_table_alias() if with_alias else None
    4074
    4075        if alias:
    4076            if self.dialect.UNNEST_COLUMN_ONLY:
    4077                if alias.args.get("columns"):
    4078                    self.raise_error("Unexpected extra column alias in unnest.")
    4079
    4080                alias.set("columns", [alias.this])
    4081                alias.set("this", None)
    4082
    4083            columns = alias.args.get("columns") or []
    4084            if offset and len(expressions) < len(columns):
    4085                offset = columns.pop()
    4086
    4087        if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
    4088            self._match(TokenType.ALIAS)
    4089            offset = self._parse_id_var(
    4090                any_token=False, tokens=self.UNNEST_OFFSET_ALIAS_TOKENS
    4091            ) or exp.to_identifier("offset")
    4092
    4093        return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
    4094
    4095    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
    4096        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
    4097        if not is_derived and not (
    4098            # ClickHouse's `FORMAT Values` is equivalent to `VALUES`
    4099            self._match_text_seq("VALUES") or self._match_text_seq("FORMAT", "VALUES")
    4100        ):
    4101            return None
    4102
    4103        expressions = self._parse_csv(self._parse_value)
    4104        alias = self._parse_table_alias()
    4105
    4106        if is_derived:
    4107            self._match_r_paren()
    4108
    4109        return self.expression(
    4110            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
    4111        )
    4112
    4113    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
    4114        if not self._match(TokenType.TABLE_SAMPLE) and not (
    4115            as_modifier and self._match_text_seq("USING", "SAMPLE")
    4116        ):
    4117            return None
    4118
    4119        bucket_numerator = None
    4120        bucket_denominator = None
    4121        bucket_field = None
    4122        percent = None
    4123        size = None
    4124        seed = None
    4125
    4126        method = self._parse_var(tokens=(TokenType.ROW,), upper=True)
    4127        matched_l_paren = self._match(TokenType.L_PAREN)
    4128
    4129        if self.TABLESAMPLE_CSV:
    4130            num = None
    4131            expressions = self._parse_csv(self._parse_primary)
    4132        else:
    4133            expressions = None
    4134            num = (
    4135                self._parse_factor()
    4136                if self._match(TokenType.NUMBER, advance=False)
    4137                else self._parse_primary() or self._parse_placeholder()
    4138            )
    4139
    4140        if self._match_text_seq("BUCKET"):
    4141            bucket_numerator = self._parse_number()
    4142            self._match_text_seq("OUT", "OF")
    4143            bucket_denominator = bucket_denominator = self._parse_number()
    4144            self._match(TokenType.ON)
    4145            bucket_field = self._parse_field()
    4146        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
    4147            percent = num
    4148        elif self._match(TokenType.ROWS) or not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
    4149            size = num
    4150        else:
    4151            percent = num
    4152
    4153        if matched_l_paren:
    4154            self._match_r_paren()
    4155
    4156        if self._match(TokenType.L_PAREN):
    4157            method = self._parse_var(upper=True)
    4158            seed = self._match(TokenType.COMMA) and self._parse_number()
    4159            self._match_r_paren()
    4160        elif self._match_texts(("SEED", "REPEATABLE")):
    4161            seed = self._parse_wrapped(self._parse_number)
    4162
    4163        if not method and self.DEFAULT_SAMPLING_METHOD:
    4164            method = exp.var(self.DEFAULT_SAMPLING_METHOD)
    4165
    4166        return self.expression(
    4167            exp.TableSample,
    4168            expressions=expressions,
    4169            method=method,
    4170            bucket_numerator=bucket_numerator,
    4171            bucket_denominator=bucket_denominator,
    4172            bucket_field=bucket_field,
    4173            percent=percent,
    4174            size=size,
    4175            seed=seed,
    4176        )
    4177
    4178    def _parse_pivots(self) -> t.Optional[t.List[exp.Pivot]]:
    4179        return list(iter(self._parse_pivot, None)) or None
    4180
    4181    def _parse_joins(self) -> t.Iterator[exp.Join]:
    4182        return iter(self._parse_join, None)
    4183
    4184    def _parse_unpivot_columns(self) -> t.Optional[exp.UnpivotColumns]:
    4185        if not self._match(TokenType.INTO):
    4186            return None
    4187
    4188        return self.expression(
    4189            exp.UnpivotColumns,
    4190            this=self._match_text_seq("NAME") and self._parse_column(),
    4191            expressions=self._match_text_seq("VALUE") and self._parse_csv(self._parse_column),
    4192        )
    4193
    4194    # https://duckdb.org/docs/sql/statements/pivot
    4195    def _parse_simplified_pivot(self, is_unpivot: t.Optional[bool] = None) -> exp.Pivot:
    4196        def _parse_on() -> t.Optional[exp.Expression]:
    4197            this = self._parse_bitwise()
    4198
    4199            if self._match(TokenType.IN):
    4200                # PIVOT ... ON col IN (row_val1, row_val2)
    4201                return self._parse_in(this)
    4202            if self._match(TokenType.ALIAS, advance=False):
    4203                # UNPIVOT ... ON (col1, col2, col3) AS row_val
    4204                return self._parse_alias(this)
    4205
    4206            return this
    4207
    4208        this = self._parse_table()
    4209        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
    4210        into = self._parse_unpivot_columns()
    4211        using = self._match(TokenType.USING) and self._parse_csv(
    4212            lambda: self._parse_alias(self._parse_function())
    4213        )
    4214        group = self._parse_group()
    4215
    4216        return self.expression(
    4217            exp.Pivot,
    4218            this=this,
    4219            expressions=expressions,
    4220            using=using,
    4221            group=group,
    4222            unpivot=is_unpivot,
    4223            into=into,
    4224        )
    4225
    4226    def _parse_pivot_in(self) -> exp.In:
    4227        def _parse_aliased_expression() -> t.Optional[exp.Expression]:
    4228            this = self._parse_select_or_expression()
    4229
    4230            self._match(TokenType.ALIAS)
    4231            alias = self._parse_bitwise()
    4232            if alias:
    4233                if isinstance(alias, exp.Column) and not alias.db:
    4234                    alias = alias.this
    4235                return self.expression(exp.PivotAlias, this=this, alias=alias)
    4236
    4237            return this
    4238
    4239        value = self._parse_column()
    4240
    4241        if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
    4242            self.raise_error("Expecting IN (")
    4243
    4244        if self._match(TokenType.ANY):
    4245            exprs: t.List[exp.Expression] = ensure_list(exp.PivotAny(this=self._parse_order()))
    4246        else:
    4247            exprs = self._parse_csv(_parse_aliased_expression)
    4248
    4249        self._match_r_paren()
    4250        return self.expression(exp.In, this=value, expressions=exprs)
    4251
    4252    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
    4253        index = self._index
    4254        include_nulls = None
    4255
    4256        if self._match(TokenType.PIVOT):
    4257            unpivot = False
    4258        elif self._match(TokenType.UNPIVOT):
    4259            unpivot = True
    4260
    4261            # https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
    4262            if self._match_text_seq("INCLUDE", "NULLS"):
    4263                include_nulls = True
    4264            elif self._match_text_seq("EXCLUDE", "NULLS"):
    4265                include_nulls = False
    4266        else:
    4267            return None
    4268
    4269        expressions = []
    4270
    4271        if not self._match(TokenType.L_PAREN):
    4272            self._retreat(index)
    4273            return None
    4274
    4275        if unpivot:
    4276            expressions = self._parse_csv(self._parse_column)
    4277        else:
    4278            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
    4279
    4280        if not expressions:
    4281            self.raise_error("Failed to parse PIVOT's aggregation list")
    4282
    4283        if not self._match(TokenType.FOR):
    4284            self.raise_error("Expecting FOR")
    4285
    4286        fields = []
    4287        while True:
    4288            field = self._try_parse(self._parse_pivot_in)
    4289            if not field:
    4290                break
    4291            fields.append(field)
    4292
    4293        default_on_null = self._match_text_seq("DEFAULT", "ON", "NULL") and self._parse_wrapped(
    4294            self._parse_bitwise
    4295        )
    4296
    4297        group = self._parse_group()
    4298
    4299        self._match_r_paren()
    4300
    4301        pivot = self.expression(
    4302            exp.Pivot,
    4303            expressions=expressions,
    4304            fields=fields,
    4305            unpivot=unpivot,
    4306            include_nulls=include_nulls,
    4307            default_on_null=default_on_null,
    4308            group=group,
    4309        )
    4310
    4311        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
    4312            pivot.set("alias", self._parse_table_alias())
    4313
    4314        if not unpivot:
    4315            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
    4316
    4317            columns: t.List[exp.Expression] = []
    4318            all_fields = []
    4319            for pivot_field in pivot.fields:
    4320                pivot_field_expressions = pivot_field.expressions
    4321
    4322                # The `PivotAny` expression corresponds to `ANY ORDER BY <column>`; we can't infer in this case.
    4323                if isinstance(seq_get(pivot_field_expressions, 0), exp.PivotAny):
    4324                    continue
    4325
    4326                all_fields.append(
    4327                    [
    4328                        fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
    4329                        for fld in pivot_field_expressions
    4330                    ]
    4331                )
    4332
    4333            if all_fields:
    4334                if names:
    4335                    all_fields.append(names)
    4336
    4337                # Generate all possible combinations of the pivot columns
    4338                # e.g PIVOT(sum(...) as total FOR year IN (2000, 2010) FOR country IN ('NL', 'US'))
    4339                # generates the product between [[2000, 2010], ['NL', 'US'], ['total']]
    4340                for fld_parts_tuple in itertools.product(*all_fields):
    4341                    fld_parts = list(fld_parts_tuple)
    4342
    4343                    if names and self.PREFIXED_PIVOT_COLUMNS:
    4344                        # Move the "name" to the front of the list
    4345                        fld_parts.insert(0, fld_parts.pop(-1))
    4346
    4347                    columns.append(exp.to_identifier("_".join(fld_parts)))
    4348
    4349            pivot.set("columns", columns)
    4350
    4351        return pivot
    4352
    4353    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
    4354        return [agg.alias for agg in aggregations if agg.alias]
    4355
    4356    def _parse_prewhere(self, skip_where_token: bool = False) -> t.Optional[exp.PreWhere]:
    4357        if not skip_where_token and not self._match(TokenType.PREWHERE):
    4358            return None
    4359
    4360        return self.expression(
    4361            exp.PreWhere, comments=self._prev_comments, this=self._parse_assignment()
    4362        )
    4363
    4364    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
    4365        if not skip_where_token and not self._match(TokenType.WHERE):
    4366            return None
    4367
    4368        return self.expression(
    4369            exp.Where, comments=self._prev_comments, this=self._parse_assignment()
    4370        )
    4371
    4372    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
    4373        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
    4374            return None
    4375
    4376        elements: t.Dict[str, t.Any] = defaultdict(list)
    4377
    4378        if self._match(TokenType.ALL):
    4379            elements["all"] = True
    4380        elif self._match(TokenType.DISTINCT):
    4381            elements["all"] = False
    4382
    4383        while True:
    4384            index = self._index
    4385
    4386            elements["expressions"].extend(
    4387                self._parse_csv(
    4388                    lambda: None
    4389                    if self._match_set((TokenType.CUBE, TokenType.ROLLUP), advance=False)
    4390                    else self._parse_assignment()
    4391                )
    4392            )
    4393
    4394            before_with_index = self._index
    4395            with_prefix = self._match(TokenType.WITH)
    4396
    4397            if self._match(TokenType.ROLLUP):
    4398                elements["rollup"].append(
    4399                    self._parse_cube_or_rollup(exp.Rollup, with_prefix=with_prefix)
    4400                )
    4401            elif self._match(TokenType.CUBE):
    4402                elements["cube"].append(
    4403                    self._parse_cube_or_rollup(exp.Cube, with_prefix=with_prefix)
    4404                )
    4405            elif self._match(TokenType.GROUPING_SETS):
    4406                elements["grouping_sets"].append(
    4407                    self.expression(
    4408                        exp.GroupingSets,
    4409                        expressions=self._parse_wrapped_csv(self._parse_grouping_set),
    4410                    )
    4411                )
    4412            elif self._match_text_seq("TOTALS"):
    4413                elements["totals"] = True  # type: ignore
    4414
    4415            if before_with_index <= self._index <= before_with_index + 1:
    4416                self._retreat(before_with_index)
    4417                break
    4418
    4419            if index == self._index:
    4420                break
    4421
    4422        return self.expression(exp.Group, **elements)  # type: ignore
    4423
    4424    def _parse_cube_or_rollup(self, kind: t.Type[E], with_prefix: bool = False) -> E:
    4425        return self.expression(
    4426            kind, expressions=[] if with_prefix else self._parse_wrapped_csv(self._parse_column)
    4427        )
    4428
    4429    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
    4430        if self._match(TokenType.L_PAREN):
    4431            grouping_set = self._parse_csv(self._parse_column)
    4432            self._match_r_paren()
    4433            return self.expression(exp.Tuple, expressions=grouping_set)
    4434
    4435        return self._parse_column()
    4436
    4437    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
    4438        if not skip_having_token and not self._match(TokenType.HAVING):
    4439            return None
    4440        return self.expression(exp.Having, this=self._parse_assignment())
    4441
    4442    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
    4443        if not self._match(TokenType.QUALIFY):
    4444            return None
    4445        return self.expression(exp.Qualify, this=self._parse_assignment())
    4446
    4447    def _parse_connect(self, skip_start_token: bool = False) -> t.Optional[exp.Connect]:
    4448        if skip_start_token:
    4449            start = None
    4450        elif self._match(TokenType.START_WITH):
    4451            start = self._parse_assignment()
    4452        else:
    4453            return None
    4454
    4455        self._match(TokenType.CONNECT_BY)
    4456        nocycle = self._match_text_seq("NOCYCLE")
    4457        self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
    4458            exp.Prior, this=self._parse_bitwise()
    4459        )
    4460        connect = self._parse_assignment()
    4461        self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
    4462
    4463        if not start and self._match(TokenType.START_WITH):
    4464            start = self._parse_assignment()
    4465
    4466        return self.expression(exp.Connect, start=start, connect=connect, nocycle=nocycle)
    4467
    4468    def _parse_name_as_expression(self) -> t.Optional[exp.Expression]:
    4469        this = self._parse_id_var(any_token=True)
    4470        if self._match(TokenType.ALIAS):
    4471            this = self.expression(exp.Alias, alias=this, this=self._parse_assignment())
    4472        return this
    4473
    4474    def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
    4475        if self._match_text_seq("INTERPOLATE"):
    4476            return self._parse_wrapped_csv(self._parse_name_as_expression)
    4477        return None
    4478
    4479    def _parse_order(
    4480        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
    4481    ) -> t.Optional[exp.Expression]:
    4482        siblings = None
    4483        if not skip_order_token and not self._match(TokenType.ORDER_BY):
    4484            if not self._match(TokenType.ORDER_SIBLINGS_BY):
    4485                return this
    4486
    4487            siblings = True
    4488
    4489        return self.expression(
    4490            exp.Order,
    4491            this=this,
    4492            expressions=self._parse_csv(self._parse_ordered),
    4493            siblings=siblings,
    4494        )
    4495
    4496    def _parse_sort(self, exp_class: t.Type[E], token: TokenType) -> t.Optional[E]:
    4497        if not self._match(token):
    4498            return None
    4499        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
    4500
    4501    def _parse_ordered(
    4502        self, parse_method: t.Optional[t.Callable] = None
    4503    ) -> t.Optional[exp.Ordered]:
    4504        this = parse_method() if parse_method else self._parse_assignment()
    4505        if not this:
    4506            return None
    4507
    4508        if this.name.upper() == "ALL" and self.dialect.SUPPORTS_ORDER_BY_ALL:
    4509            this = exp.var("ALL")
    4510
    4511        asc = self._match(TokenType.ASC)
    4512        desc = self._match(TokenType.DESC) or (asc and False)
    4513
    4514        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
    4515        is_nulls_last = self._match_text_seq("NULLS", "LAST")
    4516
    4517        nulls_first = is_nulls_first or False
    4518        explicitly_null_ordered = is_nulls_first or is_nulls_last
    4519
    4520        if (
    4521            not explicitly_null_ordered
    4522            and (
    4523                (not desc and self.dialect.NULL_ORDERING == "nulls_are_small")
    4524                or (desc and self.dialect.NULL_ORDERING != "nulls_are_small")
    4525            )
    4526            and self.dialect.NULL_ORDERING != "nulls_are_last"
    4527        ):
    4528            nulls_first = True
    4529
    4530        if self._match_text_seq("WITH", "FILL"):
    4531            with_fill = self.expression(
    4532                exp.WithFill,
    4533                **{  # type: ignore
    4534                    "from": self._match(TokenType.FROM) and self._parse_bitwise(),
    4535                    "to": self._match_text_seq("TO") and self._parse_bitwise(),
    4536                    "step": self._match_text_seq("STEP") and self._parse_bitwise(),
    4537                    "interpolate": self._parse_interpolate(),
    4538                },
    4539            )
    4540        else:
    4541            with_fill = None
    4542
    4543        return self.expression(
    4544            exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
    4545        )
    4546
    4547    def _parse_limit_options(self) -> exp.LimitOptions:
    4548        percent = self._match(TokenType.PERCENT)
    4549        rows = self._match_set((TokenType.ROW, TokenType.ROWS))
    4550        self._match_text_seq("ONLY")
    4551        with_ties = self._match_text_seq("WITH", "TIES")
    4552        return self.expression(exp.LimitOptions, percent=percent, rows=rows, with_ties=with_ties)
    4553
    4554    def _parse_limit(
    4555        self,
    4556        this: t.Optional[exp.Expression] = None,
    4557        top: bool = False,
    4558        skip_limit_token: bool = False,
    4559    ) -> t.Optional[exp.Expression]:
    4560        if skip_limit_token or self._match(TokenType.TOP if top else TokenType.LIMIT):
    4561            comments = self._prev_comments
    4562            if top:
    4563                limit_paren = self._match(TokenType.L_PAREN)
    4564                expression = self._parse_term() if limit_paren else self._parse_number()
    4565
    4566                if limit_paren:
    4567                    self._match_r_paren()
    4568
    4569                limit_options = self._parse_limit_options()
    4570            else:
    4571                limit_options = None
    4572                expression = self._parse_term()
    4573
    4574            if self._match(TokenType.COMMA):
    4575                offset = expression
    4576                expression = self._parse_term()
    4577            else:
    4578                offset = None
    4579
    4580            limit_exp = self.expression(
    4581                exp.Limit,
    4582                this=this,
    4583                expression=expression,
    4584                offset=offset,
    4585                comments=comments,
    4586                limit_options=limit_options,
    4587                expressions=self._parse_limit_by(),
    4588            )
    4589
    4590            return limit_exp
    4591
    4592        if self._match(TokenType.FETCH):
    4593            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
    4594            direction = self._prev.text.upper() if direction else "FIRST"
    4595
    4596            count = self._parse_field(tokens=self.FETCH_TOKENS)
    4597
    4598            return self.expression(
    4599                exp.Fetch,
    4600                direction=direction,
    4601                count=count,
    4602                limit_options=self._parse_limit_options(),
    4603            )
    4604
    4605        return this
    4606
    4607    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    4608        if not self._match(TokenType.OFFSET):
    4609            return this
    4610
    4611        count = self._parse_term()
    4612        self._match_set((TokenType.ROW, TokenType.ROWS))
    4613
    4614        return self.expression(
    4615            exp.Offset, this=this, expression=count, expressions=self._parse_limit_by()
    4616        )
    4617
    4618    def _can_parse_limit_or_offset(self) -> bool:
    4619        if not self._match_set(self.AMBIGUOUS_ALIAS_TOKENS, advance=False):
    4620            return False
    4621
    4622        index = self._index
    4623        result = bool(
    4624            self._try_parse(self._parse_limit, retreat=True)
    4625            or self._try_parse(self._parse_offset, retreat=True)
    4626        )
    4627        self._retreat(index)
    4628        return result
    4629
    4630    def _parse_limit_by(self) -> t.Optional[t.List[exp.Expression]]:
    4631        return self._match_text_seq("BY") and self._parse_csv(self._parse_bitwise)
    4632
    4633    def _parse_locks(self) -> t.List[exp.Lock]:
    4634        locks = []
    4635        while True:
    4636            if self._match_text_seq("FOR", "UPDATE"):
    4637                update = True
    4638            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
    4639                "LOCK", "IN", "SHARE", "MODE"
    4640            ):
    4641                update = False
    4642            else:
    4643                break
    4644
    4645            expressions = None
    4646            if self._match_text_seq("OF"):
    4647                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
    4648
    4649            wait: t.Optional[bool | exp.Expression] = None
    4650            if self._match_text_seq("NOWAIT"):
    4651                wait = True
    4652            elif self._match_text_seq("WAIT"):
    4653                wait = self._parse_primary()
    4654            elif self._match_text_seq("SKIP", "LOCKED"):
    4655                wait = False
    4656
    4657            locks.append(
    4658                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
    4659            )
    4660
    4661        return locks
    4662
    4663    def parse_set_operation(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4664        start = self._index
    4665        _, side_token, kind_token = self._parse_join_parts()
    4666
    4667        side = side_token.text if side_token else None
    4668        kind = kind_token.text if kind_token else None
    4669
    4670        if not self._match_set(self.SET_OPERATIONS):
    4671            self._retreat(start)
    4672            return None
    4673
    4674        token_type = self._prev.token_type
    4675
    4676        if token_type == TokenType.UNION:
    4677            operation: t.Type[exp.SetOperation] = exp.Union
    4678        elif token_type == TokenType.EXCEPT:
    4679            operation = exp.Except
    4680        else:
    4681            operation = exp.Intersect
    4682
    4683        comments = self._prev.comments
    4684
    4685        if self._match(TokenType.DISTINCT):
    4686            distinct: t.Optional[bool] = True
    4687        elif self._match(TokenType.ALL):
    4688            distinct = False
    4689        else:
    4690            distinct = self.dialect.SET_OP_DISTINCT_BY_DEFAULT[operation]
    4691            if distinct is None:
    4692                self.raise_error(f"Expected DISTINCT or ALL for {operation.__name__}")
    4693
    4694        by_name = self._match_text_seq("BY", "NAME") or self._match_text_seq(
    4695            "STRICT", "CORRESPONDING"
    4696        )
    4697        if self._match_text_seq("CORRESPONDING"):
    4698            by_name = True
    4699            if not side and not kind:
    4700                kind = "INNER"
    4701
    4702        on_column_list = None
    4703        if by_name and self._match_texts(("ON", "BY")):
    4704            on_column_list = self._parse_wrapped_csv(self._parse_column)
    4705
    4706        expression = self._parse_select(nested=True, parse_set_operation=False)
    4707
    4708        return self.expression(
    4709            operation,
    4710            comments=comments,
    4711            this=this,
    4712            distinct=distinct,
    4713            by_name=by_name,
    4714            expression=expression,
    4715            side=side,
    4716            kind=kind,
    4717            on=on_column_list,
    4718        )
    4719
    4720    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4721        while True:
    4722            setop = self.parse_set_operation(this)
    4723            if not setop:
    4724                break
    4725            this = setop
    4726
    4727        if isinstance(this, exp.SetOperation) and self.MODIFIERS_ATTACHED_TO_SET_OP:
    4728            expression = this.expression
    4729
    4730            if expression:
    4731                for arg in self.SET_OP_MODIFIERS:
    4732                    expr = expression.args.get(arg)
    4733                    if expr:
    4734                        this.set(arg, expr.pop())
    4735
    4736        return this
    4737
    4738    def _parse_expression(self) -> t.Optional[exp.Expression]:
    4739        return self._parse_alias(self._parse_assignment())
    4740
    4741    def _parse_assignment(self) -> t.Optional[exp.Expression]:
    4742        this = self._parse_disjunction()
    4743        if not this and self._next and self._next.token_type in self.ASSIGNMENT:
    4744            # This allows us to parse <non-identifier token> := <expr>
    4745            this = exp.column(
    4746                t.cast(str, self._advance_any(ignore_reserved=True) and self._prev.text)
    4747            )
    4748
    4749        while self._match_set(self.ASSIGNMENT):
    4750            if isinstance(this, exp.Column) and len(this.parts) == 1:
    4751                this = this.this
    4752
    4753            this = self.expression(
    4754                self.ASSIGNMENT[self._prev.token_type],
    4755                this=this,
    4756                comments=self._prev_comments,
    4757                expression=self._parse_assignment(),
    4758            )
    4759
    4760        return this
    4761
    4762    def _parse_disjunction(self) -> t.Optional[exp.Expression]:
    4763        return self._parse_tokens(self._parse_conjunction, self.DISJUNCTION)
    4764
    4765    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
    4766        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
    4767
    4768    def _parse_equality(self) -> t.Optional[exp.Expression]:
    4769        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
    4770
    4771    def _parse_comparison(self) -> t.Optional[exp.Expression]:
    4772        return self._parse_tokens(self._parse_range, self.COMPARISON)
    4773
    4774    def _parse_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    4775        this = this or self._parse_bitwise()
    4776        negate = self._match(TokenType.NOT)
    4777
    4778        if self._match_set(self.RANGE_PARSERS):
    4779            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
    4780            if not expression:
    4781                return this
    4782
    4783            this = expression
    4784        elif self._match(TokenType.ISNULL):
    4785            this = self.expression(exp.Is, this=this, expression=exp.Null())
    4786
    4787        # Postgres supports ISNULL and NOTNULL for conditions.
    4788        # https://blog.andreiavram.ro/postgresql-null-composite-type/
    4789        if self._match(TokenType.NOTNULL):
    4790            this = self.expression(exp.Is, this=this, expression=exp.Null())
    4791            this = self.expression(exp.Not, this=this)
    4792
    4793        if negate:
    4794            this = self._negate_range(this)
    4795
    4796        if self._match(TokenType.IS):
    4797            this = self._parse_is(this)
    4798
    4799        return this
    4800
    4801    def _negate_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    4802        if not this:
    4803            return this
    4804
    4805        return self.expression(exp.Not, this=this)
    4806
    4807    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4808        index = self._index - 1
    4809        negate = self._match(TokenType.NOT)
    4810
    4811        if self._match_text_seq("DISTINCT", "FROM"):
    4812            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
    4813            return self.expression(klass, this=this, expression=self._parse_bitwise())
    4814
    4815        if self._match(TokenType.JSON):
    4816            kind = self._match_texts(self.IS_JSON_PREDICATE_KIND) and self._prev.text.upper()
    4817
    4818            if self._match_text_seq("WITH"):
    4819                _with = True
    4820            elif self._match_text_seq("WITHOUT"):
    4821                _with = False
    4822            else:
    4823                _with = None
    4824
    4825            unique = self._match(TokenType.UNIQUE)
    4826            self._match_text_seq("KEYS")
    4827            expression: t.Optional[exp.Expression] = self.expression(
    4828                exp.JSON, **{"this": kind, "with": _with, "unique": unique}
    4829            )
    4830        else:
    4831            expression = self._parse_primary() or self._parse_null()
    4832            if not expression:
    4833                self._retreat(index)
    4834                return None
    4835
    4836        this = self.expression(exp.Is, this=this, expression=expression)
    4837        return self.expression(exp.Not, this=this) if negate else this
    4838
    4839    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
    4840        unnest = self._parse_unnest(with_alias=False)
    4841        if unnest:
    4842            this = self.expression(exp.In, this=this, unnest=unnest)
    4843        elif self._match_set((TokenType.L_PAREN, TokenType.L_BRACKET)):
    4844            matched_l_paren = self._prev.token_type == TokenType.L_PAREN
    4845            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
    4846
    4847            if len(expressions) == 1 and isinstance(expressions[0], exp.Query):
    4848                this = self.expression(exp.In, this=this, query=expressions[0].subquery(copy=False))
    4849            else:
    4850                this = self.expression(exp.In, this=this, expressions=expressions)
    4851
    4852            if matched_l_paren:
    4853                self._match_r_paren(this)
    4854            elif not self._match(TokenType.R_BRACKET, expression=this):
    4855                self.raise_error("Expecting ]")
    4856        else:
    4857            this = self.expression(exp.In, this=this, field=self._parse_column())
    4858
    4859        return this
    4860
    4861    def _parse_between(self, this: t.Optional[exp.Expression]) -> exp.Between:
    4862        low = self._parse_bitwise()
    4863        self._match(TokenType.AND)
    4864        high = self._parse_bitwise()
    4865        return self.expression(exp.Between, this=this, low=low, high=high)
    4866
    4867    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4868        if not self._match(TokenType.ESCAPE):
    4869            return this
    4870        return self.expression(exp.Escape, this=this, expression=self._parse_string())
    4871
    4872    def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Add | exp.Interval]:
    4873        index = self._index
    4874
    4875        if not self._match(TokenType.INTERVAL) and match_interval:
    4876            return None
    4877
    4878        if self._match(TokenType.STRING, advance=False):
    4879            this = self._parse_primary()
    4880        else:
    4881            this = self._parse_term()
    4882
    4883        if not this or (
    4884            isinstance(this, exp.Column)
    4885            and not this.table
    4886            and not this.this.quoted
    4887            and this.name.upper() == "IS"
    4888        ):
    4889            self._retreat(index)
    4890            return None
    4891
    4892        unit = self._parse_function() or (
    4893            not self._match(TokenType.ALIAS, advance=False)
    4894            and self._parse_var(any_token=True, upper=True)
    4895        )
    4896
    4897        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
    4898        # each INTERVAL expression into this canonical form so it's easy to transpile
    4899        if this and this.is_number:
    4900            this = exp.Literal.string(this.to_py())
    4901        elif this and this.is_string:
    4902            parts = exp.INTERVAL_STRING_RE.findall(this.name)
    4903            if parts and unit:
    4904                # Unconsume the eagerly-parsed unit, since the real unit was part of the string
    4905                unit = None
    4906                self._retreat(self._index - 1)
    4907
    4908            if len(parts) == 1:
    4909                this = exp.Literal.string(parts[0][0])
    4910                unit = self.expression(exp.Var, this=parts[0][1].upper())
    4911        if self.INTERVAL_SPANS and self._match_text_seq("TO"):
    4912            unit = self.expression(
    4913                exp.IntervalSpan, this=unit, expression=self._parse_var(any_token=True, upper=True)
    4914            )
    4915
    4916        interval = self.expression(exp.Interval, this=this, unit=unit)
    4917
    4918        index = self._index
    4919        self._match(TokenType.PLUS)
    4920
    4921        # Convert INTERVAL 'val_1' unit_1 [+] ... [+] 'val_n' unit_n into a sum of intervals
    4922        if self._match_set((TokenType.STRING, TokenType.NUMBER), advance=False):
    4923            return self.expression(
    4924                exp.Add, this=interval, expression=self._parse_interval(match_interval=False)
    4925            )
    4926
    4927        self._retreat(index)
    4928        return interval
    4929
    4930    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
    4931        this = self._parse_term()
    4932
    4933        while True:
    4934            if self._match_set(self.BITWISE):
    4935                this = self.expression(
    4936                    self.BITWISE[self._prev.token_type],
    4937                    this=this,
    4938                    expression=self._parse_term(),
    4939                )
    4940            elif self.dialect.DPIPE_IS_STRING_CONCAT and self._match(TokenType.DPIPE):
    4941                this = self.expression(
    4942                    exp.DPipe,
    4943                    this=this,
    4944                    expression=self._parse_term(),
    4945                    safe=not self.dialect.STRICT_STRING_CONCAT,
    4946                )
    4947            elif self._match(TokenType.DQMARK):
    4948                this = self.expression(
    4949                    exp.Coalesce, this=this, expressions=ensure_list(self._parse_term())
    4950                )
    4951            elif self._match_pair(TokenType.LT, TokenType.LT):
    4952                this = self.expression(
    4953                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
    4954                )
    4955            elif self._match_pair(TokenType.GT, TokenType.GT):
    4956                this = self.expression(
    4957                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
    4958                )
    4959            else:
    4960                break
    4961
    4962        return this
    4963
    4964    def _parse_term(self) -> t.Optional[exp.Expression]:
    4965        this = self._parse_factor()
    4966
    4967        while self._match_set(self.TERM):
    4968            klass = self.TERM[self._prev.token_type]
    4969            comments = self._prev_comments
    4970            expression = self._parse_factor()
    4971
    4972            this = self.expression(klass, this=this, comments=comments, expression=expression)
    4973
    4974            if isinstance(this, exp.Collate):
    4975                expr = this.expression
    4976
    4977                # Preserve collations such as pg_catalog."default" (Postgres) as columns, otherwise
    4978                # fallback to Identifier / Var
    4979                if isinstance(expr, exp.Column) and len(expr.parts) == 1:
    4980                    ident = expr.this
    4981                    if isinstance(ident, exp.Identifier):
    4982                        this.set("expression", ident if ident.quoted else exp.var(ident.name))
    4983
    4984        return this
    4985
    4986    def _parse_factor(self) -> t.Optional[exp.Expression]:
    4987        parse_method = self._parse_exponent if self.EXPONENT else self._parse_unary
    4988        this = parse_method()
    4989
    4990        while self._match_set(self.FACTOR):
    4991            klass = self.FACTOR[self._prev.token_type]
    4992            comments = self._prev_comments
    4993            expression = parse_method()
    4994
    4995            if not expression and klass is exp.IntDiv and self._prev.text.isalpha():
    4996                self._retreat(self._index - 1)
    4997                return this
    4998
    4999            this = self.expression(klass, this=this, comments=comments, expression=expression)
    5000
    5001            if isinstance(this, exp.Div):
    5002                this.args["typed"] = self.dialect.TYPED_DIVISION
    5003                this.args["safe"] = self.dialect.SAFE_DIVISION
    5004
    5005        return this
    5006
    5007    def _parse_exponent(self) -> t.Optional[exp.Expression]:
    5008        return self._parse_tokens(self._parse_unary, self.EXPONENT)
    5009
    5010    def _parse_unary(self) -> t.Optional[exp.Expression]:
    5011        if self._match_set(self.UNARY_PARSERS):
    5012            return self.UNARY_PARSERS[self._prev.token_type](self)
    5013        return self._parse_at_time_zone(self._parse_type())
    5014
    5015    def _parse_type(
    5016        self, parse_interval: bool = True, fallback_to_identifier: bool = False
    5017    ) -> t.Optional[exp.Expression]:
    5018        interval = parse_interval and self._parse_interval()
    5019        if interval:
    5020            return interval
    5021
    5022        index = self._index
    5023        data_type = self._parse_types(check_func=True, allow_identifiers=False)
    5024
    5025        # parse_types() returns a Cast if we parsed BQ's inline constructor <type>(<values>) e.g.
    5026        # STRUCT<a INT, b STRING>(1, 'foo'), which is canonicalized to CAST(<values> AS <type>)
    5027        if isinstance(data_type, exp.Cast):
    5028            # This constructor can contain ops directly after it, for instance struct unnesting:
    5029            # STRUCT<a INT, b STRING>(1, 'foo').* --> CAST(STRUCT(1, 'foo') AS STRUCT<a iNT, b STRING).*
    5030            return self._parse_column_ops(data_type)
    5031
    5032        if data_type:
    5033            index2 = self._index
    5034            this = self._parse_primary()
    5035
    5036            if isinstance(this, exp.Literal):
    5037                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
    5038                if parser:
    5039                    return parser(self, this, data_type)
    5040
    5041                return self.expression(exp.Cast, this=this, to=data_type)
    5042
    5043            # The expressions arg gets set by the parser when we have something like DECIMAL(38, 0)
    5044            # in the input SQL. In that case, we'll produce these tokens: DECIMAL ( 38 , 0 )
    5045            #
    5046            # If the index difference here is greater than 1, that means the parser itself must have
    5047            # consumed additional tokens such as the DECIMAL scale and precision in the above example.
    5048            #
    5049            # If it's not greater than 1, then it must be 1, because we've consumed at least the type
    5050            # keyword, meaning that the expressions arg of the DataType must have gotten set by a
    5051            # callable in the TYPE_CONVERTERS mapping. For example, Snowflake converts DECIMAL to
    5052            # DECIMAL(38, 0)) in order to facilitate the data type's transpilation.
    5053            #
    5054            # In these cases, we don't really want to return the converted type, but instead retreat
    5055            # and try to parse a Column or Identifier in the section below.
    5056            if data_type.expressions and index2 - index > 1:
    5057                self._retreat(index2)
    5058                return self._parse_column_ops(data_type)
    5059
    5060            self._retreat(index)
    5061
    5062        if fallback_to_identifier:
    5063            return self._parse_id_var()
    5064
    5065        this = self._parse_column()
    5066        return this and self._parse_column_ops(this)
    5067
    5068    def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
    5069        this = self._parse_type()
    5070        if not this:
    5071            return None
    5072
    5073        if isinstance(this, exp.Column) and not this.table:
    5074            this = exp.var(this.name.upper())
    5075
    5076        return self.expression(
    5077            exp.DataTypeParam, this=this, expression=self._parse_var(any_token=True)
    5078        )
    5079
    5080    def _parse_types(
    5081        self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
    5082    ) -> t.Optional[exp.Expression]:
    5083        index = self._index
    5084
    5085        this: t.Optional[exp.Expression] = None
    5086        prefix = self._match_text_seq("SYSUDTLIB", ".")
    5087
    5088        if not self._match_set(self.TYPE_TOKENS):
    5089            identifier = allow_identifiers and self._parse_id_var(
    5090                any_token=False, tokens=(TokenType.VAR,)
    5091            )
    5092            if isinstance(identifier, exp.Identifier):
    5093                tokens = self.dialect.tokenize(identifier.sql(dialect=self.dialect))
    5094
    5095                if len(tokens) != 1:
    5096                    self.raise_error("Unexpected identifier", self._prev)
    5097
    5098                if tokens[0].token_type in self.TYPE_TOKENS:
    5099                    self._prev = tokens[0]
    5100                elif self.dialect.SUPPORTS_USER_DEFINED_TYPES:
    5101                    type_name = identifier.name
    5102
    5103                    while self._match(TokenType.DOT):
    5104                        type_name = f"{type_name}.{self._advance_any() and self._prev.text}"
    5105
    5106                    this = exp.DataType.build(type_name, udt=True)
    5107                else:
    5108                    self._retreat(self._index - 1)
    5109                    return None
    5110            else:
    5111                return None
    5112
    5113        type_token = self._prev.token_type
    5114
    5115        if type_token == TokenType.PSEUDO_TYPE:
    5116            return self.expression(exp.PseudoType, this=self._prev.text.upper())
    5117
    5118        if type_token == TokenType.OBJECT_IDENTIFIER:
    5119            return self.expression(exp.ObjectIdentifier, this=self._prev.text.upper())
    5120
    5121        # https://materialize.com/docs/sql/types/map/
    5122        if type_token == TokenType.MAP and self._match(TokenType.L_BRACKET):
    5123            key_type = self._parse_types(
    5124                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    5125            )
    5126            if not self._match(TokenType.FARROW):
    5127                self._retreat(index)
    5128                return None
    5129
    5130            value_type = self._parse_types(
    5131                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    5132            )
    5133            if not self._match(TokenType.R_BRACKET):
    5134                self._retreat(index)
    5135                return None
    5136
    5137            return exp.DataType(
    5138                this=exp.DataType.Type.MAP,
    5139                expressions=[key_type, value_type],
    5140                nested=True,
    5141                prefix=prefix,
    5142            )
    5143
    5144        nested = type_token in self.NESTED_TYPE_TOKENS
    5145        is_struct = type_token in self.STRUCT_TYPE_TOKENS
    5146        is_aggregate = type_token in self.AGGREGATE_TYPE_TOKENS
    5147        expressions = None
    5148        maybe_func = False
    5149
    5150        if self._match(TokenType.L_PAREN):
    5151            if is_struct:
    5152                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
    5153            elif nested:
    5154                expressions = self._parse_csv(
    5155                    lambda: self._parse_types(
    5156                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    5157                    )
    5158                )
    5159                if type_token == TokenType.NULLABLE and len(expressions) == 1:
    5160                    this = expressions[0]
    5161                    this.set("nullable", True)
    5162                    self._match_r_paren()
    5163                    return this
    5164            elif type_token in self.ENUM_TYPE_TOKENS:
    5165                expressions = self._parse_csv(self._parse_equality)
    5166            elif is_aggregate:
    5167                func_or_ident = self._parse_function(anonymous=True) or self._parse_id_var(
    5168                    any_token=False, tokens=(TokenType.VAR, TokenType.ANY)
    5169                )
    5170                if not func_or_ident:
    5171                    return None
    5172                expressions = [func_or_ident]
    5173                if self._match(TokenType.COMMA):
    5174                    expressions.extend(
    5175                        self._parse_csv(
    5176                            lambda: self._parse_types(
    5177                                check_func=check_func,
    5178                                schema=schema,
    5179                                allow_identifiers=allow_identifiers,
    5180                            )
    5181                        )
    5182                    )
    5183            else:
    5184                expressions = self._parse_csv(self._parse_type_size)
    5185
    5186                # https://docs.snowflake.com/en/sql-reference/data-types-vector
    5187                if type_token == TokenType.VECTOR and len(expressions) == 2:
    5188                    expressions[0] = exp.DataType.build(expressions[0].name, dialect=self.dialect)
    5189
    5190            if not expressions or not self._match(TokenType.R_PAREN):
    5191                self._retreat(index)
    5192                return None
    5193
    5194            maybe_func = True
    5195
    5196        values: t.Optional[t.List[exp.Expression]] = None
    5197
    5198        if nested and self._match(TokenType.LT):
    5199            if is_struct:
    5200                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
    5201            else:
    5202                expressions = self._parse_csv(
    5203                    lambda: self._parse_types(
    5204                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
    5205                    )
    5206                )
    5207
    5208            if not self._match(TokenType.GT):
    5209                self.raise_error("Expecting >")
    5210
    5211            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
    5212                values = self._parse_csv(self._parse_assignment)
    5213                if not values and is_struct:
    5214                    values = None
    5215                    self._retreat(self._index - 1)
    5216                else:
    5217                    self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
    5218
    5219        if type_token in self.TIMESTAMPS:
    5220            if self._match_text_seq("WITH", "TIME", "ZONE"):
    5221                maybe_func = False
    5222                tz_type = (
    5223                    exp.DataType.Type.TIMETZ
    5224                    if type_token in self.TIMES
    5225                    else exp.DataType.Type.TIMESTAMPTZ
    5226                )
    5227                this = exp.DataType(this=tz_type, expressions=expressions)
    5228            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
    5229                maybe_func = False
    5230                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
    5231            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
    5232                maybe_func = False
    5233        elif type_token == TokenType.INTERVAL:
    5234            unit = self._parse_var(upper=True)
    5235            if unit:
    5236                if self._match_text_seq("TO"):
    5237                    unit = exp.IntervalSpan(this=unit, expression=self._parse_var(upper=True))
    5238
    5239                this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
    5240            else:
    5241                this = self.expression(exp.DataType, this=exp.DataType.Type.INTERVAL)
    5242
    5243        if maybe_func and check_func:
    5244            index2 = self._index
    5245            peek = self._parse_string()
    5246
    5247            if not peek:
    5248                self._retreat(index)
    5249                return None
    5250
    5251            self._retreat(index2)
    5252
    5253        if not this:
    5254            if self._match_text_seq("UNSIGNED"):
    5255                unsigned_type_token = self.SIGNED_TO_UNSIGNED_TYPE_TOKEN.get(type_token)
    5256                if not unsigned_type_token:
    5257                    self.raise_error(f"Cannot convert {type_token.value} to unsigned.")
    5258
    5259                type_token = unsigned_type_token or type_token
    5260
    5261            this = exp.DataType(
    5262                this=exp.DataType.Type[type_token.value],
    5263                expressions=expressions,
    5264                nested=nested,
    5265                prefix=prefix,
    5266            )
    5267
    5268            # Empty arrays/structs are allowed
    5269            if values is not None:
    5270                cls = exp.Struct if is_struct else exp.Array
    5271                this = exp.cast(cls(expressions=values), this, copy=False)
    5272
    5273        elif expressions:
    5274            this.set("expressions", expressions)
    5275
    5276        # https://materialize.com/docs/sql/types/list/#type-name
    5277        while self._match(TokenType.LIST):
    5278            this = exp.DataType(this=exp.DataType.Type.LIST, expressions=[this], nested=True)
    5279
    5280        index = self._index
    5281
    5282        # Postgres supports the INT ARRAY[3] syntax as a synonym for INT[3]
    5283        matched_array = self._match(TokenType.ARRAY)
    5284
    5285        while self._curr:
    5286            datatype_token = self._prev.token_type
    5287            matched_l_bracket = self._match(TokenType.L_BRACKET)
    5288
    5289            if (not matched_l_bracket and not matched_array) or (
    5290                datatype_token == TokenType.ARRAY and self._match(TokenType.R_BRACKET)
    5291            ):
    5292                # Postgres allows casting empty arrays such as ARRAY[]::INT[],
    5293                # not to be confused with the fixed size array parsing
    5294                break
    5295
    5296            matched_array = False
    5297            values = self._parse_csv(self._parse_assignment) or None
    5298            if (
    5299                values
    5300                and not schema
    5301                and (
    5302                    not self.dialect.SUPPORTS_FIXED_SIZE_ARRAYS or datatype_token == TokenType.ARRAY
    5303                )
    5304            ):
    5305                # Retreating here means that we should not parse the following values as part of the data type, e.g. in DuckDB
    5306                # ARRAY[1] should retreat and instead be parsed into exp.Array in contrast to INT[x][y] which denotes a fixed-size array data type
    5307                self._retreat(index)
    5308                break
    5309
    5310            this = exp.DataType(
    5311                this=exp.DataType.Type.ARRAY, expressions=[this], values=values, nested=True
    5312            )
    5313            self._match(TokenType.R_BRACKET)
    5314
    5315        if self.TYPE_CONVERTERS and isinstance(this.this, exp.DataType.Type):
    5316            converter = self.TYPE_CONVERTERS.get(this.this)
    5317            if converter:
    5318                this = converter(t.cast(exp.DataType, this))
    5319
    5320        return this
    5321
    5322    def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
    5323        index = self._index
    5324
    5325        if (
    5326            self._curr
    5327            and self._next
    5328            and self._curr.token_type in self.TYPE_TOKENS
    5329            and self._next.token_type in self.TYPE_TOKENS
    5330        ):
    5331            # Takes care of special cases like `STRUCT<list ARRAY<...>>` where the identifier is also a
    5332            # type token. Without this, the list will be parsed as a type and we'll eventually crash
    5333            this = self._parse_id_var()
    5334        else:
    5335            this = (
    5336                self._parse_type(parse_interval=False, fallback_to_identifier=True)
    5337                or self._parse_id_var()
    5338            )
    5339
    5340        self._match(TokenType.COLON)
    5341
    5342        if (
    5343            type_required
    5344            and not isinstance(this, exp.DataType)
    5345            and not self._match_set(self.TYPE_TOKENS, advance=False)
    5346        ):
    5347            self._retreat(index)
    5348            return self._parse_types()
    5349
    5350        return self._parse_column_def(this)
    5351
    5352    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    5353        if not self._match_text_seq("AT", "TIME", "ZONE"):
    5354            return this
    5355        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
    5356
    5357    def _parse_column(self) -> t.Optional[exp.Expression]:
    5358        this = self._parse_column_reference()
    5359        column = self._parse_column_ops(this) if this else self._parse_bracket(this)
    5360
    5361        if self.dialect.SUPPORTS_COLUMN_JOIN_MARKS and column:
    5362            column.set("join_mark", self._match(TokenType.JOIN_MARKER))
    5363
    5364        return column
    5365
    5366    def _parse_column_reference(self) -> t.Optional[exp.Expression]:
    5367        this = self._parse_field()
    5368        if (
    5369            not this
    5370            and self._match(TokenType.VALUES, advance=False)
    5371            and self.VALUES_FOLLOWED_BY_PAREN
    5372            and (not self._next or self._next.token_type != TokenType.L_PAREN)
    5373        ):
    5374            this = self._parse_id_var()
    5375
    5376        if isinstance(this, exp.Identifier):
    5377            # We bubble up comments from the Identifier to the Column
    5378            this = self.expression(exp.Column, comments=this.pop_comments(), this=this)
    5379
    5380        return this
    5381
    5382    def _parse_colon_as_variant_extract(
    5383        self, this: t.Optional[exp.Expression]
    5384    ) -> t.Optional[exp.Expression]:
    5385        casts = []
    5386        json_path = []
    5387        escape = None
    5388
    5389        while self._match(TokenType.COLON):
    5390            start_index = self._index
    5391
    5392            # Snowflake allows reserved keywords as json keys but advance_any() excludes TokenType.SELECT from any_tokens=True
    5393            path = self._parse_column_ops(
    5394                self._parse_field(any_token=True, tokens=(TokenType.SELECT,))
    5395            )
    5396
    5397            # The cast :: operator has a lower precedence than the extraction operator :, so
    5398            # we rearrange the AST appropriately to avoid casting the JSON path
    5399            while isinstance(path, exp.Cast):
    5400                casts.append(path.to)
    5401                path = path.this
    5402
    5403            if casts:
    5404                dcolon_offset = next(
    5405                    i
    5406                    for i, t in enumerate(self._tokens[start_index:])
    5407                    if t.token_type == TokenType.DCOLON
    5408                )
    5409                end_token = self._tokens[start_index + dcolon_offset - 1]
    5410            else:
    5411                end_token = self._prev
    5412
    5413            if path:
    5414                # Escape single quotes from Snowflake's colon extraction (e.g. col:"a'b") as
    5415                # it'll roundtrip to a string literal in GET_PATH
    5416                if isinstance(path, exp.Identifier) and path.quoted:
    5417                    escape = True
    5418
    5419                json_path.append(self._find_sql(self._tokens[start_index], end_token))
    5420
    5421        # The VARIANT extract in Snowflake/Databricks is parsed as a JSONExtract; Snowflake uses the json_path in GET_PATH() while
    5422        # Databricks transforms it back to the colon/dot notation
    5423        if json_path:
    5424            json_path_expr = self.dialect.to_json_path(exp.Literal.string(".".join(json_path)))
    5425
    5426            if json_path_expr:
    5427                json_path_expr.set("escape", escape)
    5428
    5429            this = self.expression(
    5430                exp.JSONExtract,
    5431                this=this,
    5432                expression=json_path_expr,
    5433                variant_extract=True,
    5434            )
    5435
    5436            while casts:
    5437                this = self.expression(exp.Cast, this=this, to=casts.pop())
    5438
    5439        return this
    5440
    5441    def _parse_dcolon(self) -> t.Optional[exp.Expression]:
    5442        return self._parse_types()
    5443
    5444    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    5445        this = self._parse_bracket(this)
    5446
    5447        while self._match_set(self.COLUMN_OPERATORS):
    5448            op_token = self._prev.token_type
    5449            op = self.COLUMN_OPERATORS.get(op_token)
    5450
    5451            if op_token in (TokenType.DCOLON, TokenType.DOTCOLON):
    5452                field = self._parse_dcolon()
    5453                if not field:
    5454                    self.raise_error("Expected type")
    5455            elif op and self._curr:
    5456                field = self._parse_column_reference() or self._parse_bracket()
    5457                if isinstance(field, exp.Column) and self._match(TokenType.DOT, advance=False):
    5458                    field = self._parse_column_ops(field)
    5459            else:
    5460                field = self._parse_field(any_token=True, anonymous_func=True)
    5461
    5462            if isinstance(field, (exp.Func, exp.Window)) and this:
    5463                # BQ & snowflake allow function calls like x.y.count(...), SAFE.SUBSTR(...) etc
    5464                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
    5465                this = exp.replace_tree(
    5466                    this,
    5467                    lambda n: (
    5468                        self.expression(exp.Dot, this=n.args.get("table"), expression=n.this)
    5469                        if n.table
    5470                        else n.this
    5471                    )
    5472                    if isinstance(n, exp.Column)
    5473                    else n,
    5474                )
    5475
    5476            if op:
    5477                this = op(self, this, field)
    5478            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
    5479                this = self.expression(
    5480                    exp.Column,
    5481                    comments=this.comments,
    5482                    this=field,
    5483                    table=this.this,
    5484                    db=this.args.get("table"),
    5485                    catalog=this.args.get("db"),
    5486                )
    5487            elif isinstance(field, exp.Window):
    5488                # Move the exp.Dot's to the window's function
    5489                window_func = self.expression(exp.Dot, this=this, expression=field.this)
    5490                field.set("this", window_func)
    5491                this = field
    5492            else:
    5493                this = self.expression(exp.Dot, this=this, expression=field)
    5494
    5495            if field and field.comments:
    5496                t.cast(exp.Expression, this).add_comments(field.pop_comments())
    5497
    5498            this = self._parse_bracket(this)
    5499
    5500        return self._parse_colon_as_variant_extract(this) if self.COLON_IS_VARIANT_EXTRACT else this
    5501
    5502    def _parse_primary(self) -> t.Optional[exp.Expression]:
    5503        if self._match_set(self.PRIMARY_PARSERS):
    5504            token_type = self._prev.token_type
    5505            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
    5506
    5507            if token_type == TokenType.STRING:
    5508                expressions = [primary]
    5509                while self._match(TokenType.STRING):
    5510                    expressions.append(exp.Literal.string(self._prev.text))
    5511
    5512                if len(expressions) > 1:
    5513                    return self.expression(exp.Concat, expressions=expressions)
    5514
    5515            return primary
    5516
    5517        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
    5518            return exp.Literal.number(f"0.{self._prev.text}")
    5519
    5520        if self._match(TokenType.L_PAREN):
    5521            comments = self._prev_comments
    5522            query = self._parse_select()
    5523
    5524            if query:
    5525                expressions = [query]
    5526            else:
    5527                expressions = self._parse_expressions()
    5528
    5529            this = self._parse_query_modifiers(seq_get(expressions, 0))
    5530
    5531            if not this and self._match(TokenType.R_PAREN, advance=False):
    5532                this = self.expression(exp.Tuple)
    5533            elif isinstance(this, exp.UNWRAPPED_QUERIES):
    5534                this = self._parse_subquery(this=this, parse_alias=False)
    5535            elif isinstance(this, exp.Subquery):
    5536                this = self._parse_subquery(
    5537                    this=self._parse_set_operations(this), parse_alias=False
    5538                )
    5539            elif len(expressions) > 1 or self._prev.token_type == TokenType.COMMA:
    5540                this = self.expression(exp.Tuple, expressions=expressions)
    5541            else:
    5542                this = self.expression(exp.Paren, this=this)
    5543
    5544            if this:
    5545                this.add_comments(comments)
    5546
    5547            self._match_r_paren(expression=this)
    5548            return this
    5549
    5550        return None
    5551
    5552    def _parse_field(
    5553        self,
    5554        any_token: bool = False,
    5555        tokens: t.Optional[t.Collection[TokenType]] = None,
    5556        anonymous_func: bool = False,
    5557    ) -> t.Optional[exp.Expression]:
    5558        if anonymous_func:
    5559            field = (
    5560                self._parse_function(anonymous=anonymous_func, any_token=any_token)
    5561                or self._parse_primary()
    5562            )
    5563        else:
    5564            field = self._parse_primary() or self._parse_function(
    5565                anonymous=anonymous_func, any_token=any_token
    5566            )
    5567        return field or self._parse_id_var(any_token=any_token, tokens=tokens)
    5568
    5569    def _parse_function(
    5570        self,
    5571        functions: t.Optional[t.Dict[str, t.Callable]] = None,
    5572        anonymous: bool = False,
    5573        optional_parens: bool = True,
    5574        any_token: bool = False,
    5575    ) -> t.Optional[exp.Expression]:
    5576        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
    5577        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
    5578        fn_syntax = False
    5579        if (
    5580            self._match(TokenType.L_BRACE, advance=False)
    5581            and self._next
    5582            and self._next.text.upper() == "FN"
    5583        ):
    5584            self._advance(2)
    5585            fn_syntax = True
    5586
    5587        func = self._parse_function_call(
    5588            functions=functions,
    5589            anonymous=anonymous,
    5590            optional_parens=optional_parens,
    5591            any_token=any_token,
    5592        )
    5593
    5594        if fn_syntax:
    5595            self._match(TokenType.R_BRACE)
    5596
    5597        return func
    5598
    5599    def _parse_function_call(
    5600        self,
    5601        functions: t.Optional[t.Dict[str, t.Callable]] = None,
    5602        anonymous: bool = False,
    5603        optional_parens: bool = True,
    5604        any_token: bool = False,
    5605    ) -> t.Optional[exp.Expression]:
    5606        if not self._curr:
    5607            return None
    5608
    5609        comments = self._curr.comments
    5610        token_type = self._curr.token_type
    5611        this = self._curr.text
    5612        upper = this.upper()
    5613
    5614        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
    5615        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
    5616            self._advance()
    5617            return self._parse_window(parser(self))
    5618
    5619        if not self._next or self._next.token_type != TokenType.L_PAREN:
    5620            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
    5621                self._advance()
    5622                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
    5623
    5624            return None
    5625
    5626        if any_token:
    5627            if token_type in self.RESERVED_TOKENS:
    5628                return None
    5629        elif token_type not in self.FUNC_TOKENS:
    5630            return None
    5631
    5632        self._advance(2)
    5633
    5634        parser = self.FUNCTION_PARSERS.get(upper)
    5635        if parser and not anonymous:
    5636            this = parser(self)
    5637        else:
    5638            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
    5639
    5640            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
    5641                this = self.expression(
    5642                    subquery_predicate, comments=comments, this=self._parse_select()
    5643                )
    5644                self._match_r_paren()
    5645                return this
    5646
    5647            if functions is None:
    5648                functions = self.FUNCTIONS
    5649
    5650            function = functions.get(upper)
    5651            known_function = function and not anonymous
    5652
    5653            alias = not known_function or upper in self.FUNCTIONS_WITH_ALIASED_ARGS
    5654            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
    5655
    5656            post_func_comments = self._curr and self._curr.comments
    5657            if known_function and post_func_comments:
    5658                # If the user-inputted comment "/* sqlglot.anonymous */" is following the function
    5659                # call we'll construct it as exp.Anonymous, even if it's "known"
    5660                if any(
    5661                    comment.lstrip().startswith(exp.SQLGLOT_ANONYMOUS)
    5662                    for comment in post_func_comments
    5663                ):
    5664                    known_function = False
    5665
    5666            if alias and known_function:
    5667                args = self._kv_to_prop_eq(args)
    5668
    5669            if known_function:
    5670                func_builder = t.cast(t.Callable, function)
    5671
    5672                if "dialect" in func_builder.__code__.co_varnames:
    5673                    func = func_builder(args, dialect=self.dialect)
    5674                else:
    5675                    func = func_builder(args)
    5676
    5677                func = self.validate_expression(func, args)
    5678                if self.dialect.PRESERVE_ORIGINAL_NAMES:
    5679                    func.meta["name"] = this
    5680
    5681                this = func
    5682            else:
    5683                if token_type == TokenType.IDENTIFIER:
    5684                    this = exp.Identifier(this=this, quoted=True)
    5685                this = self.expression(exp.Anonymous, this=this, expressions=args)
    5686
    5687        if isinstance(this, exp.Expression):
    5688            this.add_comments(comments)
    5689
    5690        self._match_r_paren(this)
    5691        return self._parse_window(this)
    5692
    5693    def _to_prop_eq(self, expression: exp.Expression, index: int) -> exp.Expression:
    5694        return expression
    5695
    5696    def _kv_to_prop_eq(self, expressions: t.List[exp.Expression]) -> t.List[exp.Expression]:
    5697        transformed = []
    5698
    5699        for index, e in enumerate(expressions):
    5700            if isinstance(e, self.KEY_VALUE_DEFINITIONS):
    5701                if isinstance(e, exp.Alias):
    5702                    e = self.expression(exp.PropertyEQ, this=e.args.get("alias"), expression=e.this)
    5703
    5704                if not isinstance(e, exp.PropertyEQ):
    5705                    e = self.expression(
    5706                        exp.PropertyEQ, this=exp.to_identifier(e.this.name), expression=e.expression
    5707                    )
    5708
    5709                if isinstance(e.this, exp.Column):
    5710                    e.this.replace(e.this.this)
    5711            else:
    5712                e = self._to_prop_eq(e, index)
    5713
    5714            transformed.append(e)
    5715
    5716        return transformed
    5717
    5718    def _parse_user_defined_function_expression(self) -> t.Optional[exp.Expression]:
    5719        return self._parse_statement()
    5720
    5721    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
    5722        return self._parse_column_def(this=self._parse_id_var(), computed_column=False)
    5723
    5724    def _parse_user_defined_function(
    5725        self, kind: t.Optional[TokenType] = None
    5726    ) -> t.Optional[exp.Expression]:
    5727        this = self._parse_table_parts(schema=True)
    5728
    5729        if not self._match(TokenType.L_PAREN):
    5730            return this
    5731
    5732        expressions = self._parse_csv(self._parse_function_parameter)
    5733        self._match_r_paren()
    5734        return self.expression(
    5735            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
    5736        )
    5737
    5738    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
    5739        literal = self._parse_primary()
    5740        if literal:
    5741            return self.expression(exp.Introducer, this=token.text, expression=literal)
    5742
    5743        return self.expression(exp.Identifier, this=token.text)
    5744
    5745    def _parse_session_parameter(self) -> exp.SessionParameter:
    5746        kind = None
    5747        this = self._parse_id_var() or self._parse_primary()
    5748
    5749        if this and self._match(TokenType.DOT):
    5750            kind = this.name
    5751            this = self._parse_var() or self._parse_primary()
    5752
    5753        return self.expression(exp.SessionParameter, this=this, kind=kind)
    5754
    5755    def _parse_lambda_arg(self) -> t.Optional[exp.Expression]:
    5756        return self._parse_id_var()
    5757
    5758    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
    5759        index = self._index
    5760
    5761        if self._match(TokenType.L_PAREN):
    5762            expressions = t.cast(
    5763                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_lambda_arg)
    5764            )
    5765
    5766            if not self._match(TokenType.R_PAREN):
    5767                self._retreat(index)
    5768        else:
    5769            expressions = [self._parse_lambda_arg()]
    5770
    5771        if self._match_set(self.LAMBDAS):
    5772            return self.LAMBDAS[self._prev.token_type](self, expressions)
    5773
    5774        self._retreat(index)
    5775
    5776        this: t.Optional[exp.Expression]
    5777
    5778        if self._match(TokenType.DISTINCT):
    5779            this = self.expression(
    5780                exp.Distinct, expressions=self._parse_csv(self._parse_assignment)
    5781            )
    5782        else:
    5783            this = self._parse_select_or_expression(alias=alias)
    5784
    5785        return self._parse_limit(
    5786            self._parse_order(self._parse_having_max(self._parse_respect_or_ignore_nulls(this)))
    5787        )
    5788
    5789    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    5790        index = self._index
    5791        if not self._match(TokenType.L_PAREN):
    5792            return this
    5793
    5794        # Disambiguate between schema and subquery/CTE, e.g. in INSERT INTO table (<expr>),
    5795        # expr can be of both types
    5796        if self._match_set(self.SELECT_START_TOKENS):
    5797            self._retreat(index)
    5798            return this
    5799        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
    5800        self._match_r_paren()
    5801        return self.expression(exp.Schema, this=this, expressions=args)
    5802
    5803    def _parse_field_def(self) -> t.Optional[exp.Expression]:
    5804        return self._parse_column_def(self._parse_field(any_token=True))
    5805
    5806    def _parse_column_def(
    5807        self, this: t.Optional[exp.Expression], computed_column: bool = True
    5808    ) -> t.Optional[exp.Expression]:
    5809        # column defs are not really columns, they're identifiers
    5810        if isinstance(this, exp.Column):
    5811            this = this.this
    5812
    5813        if not computed_column:
    5814            self._match(TokenType.ALIAS)
    5815
    5816        kind = self._parse_types(schema=True)
    5817
    5818        if self._match_text_seq("FOR", "ORDINALITY"):
    5819            return self.expression(exp.ColumnDef, this=this, ordinality=True)
    5820
    5821        constraints: t.List[exp.Expression] = []
    5822
    5823        if (not kind and self._match(TokenType.ALIAS)) or self._match_texts(
    5824            ("ALIAS", "MATERIALIZED")
    5825        ):
    5826            persisted = self._prev.text.upper() == "MATERIALIZED"
    5827            constraint_kind = exp.ComputedColumnConstraint(
    5828                this=self._parse_assignment(),
    5829                persisted=persisted or self._match_text_seq("PERSISTED"),
    5830                not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
    5831            )
    5832            constraints.append(self.expression(exp.ColumnConstraint, kind=constraint_kind))
    5833        elif (
    5834            kind
    5835            and self._match(TokenType.ALIAS, advance=False)
    5836            and (
    5837                not self.WRAPPED_TRANSFORM_COLUMN_CONSTRAINT
    5838                or (self._next and self._next.token_type == TokenType.L_PAREN)
    5839            )
    5840        ):
    5841            self._advance()
    5842            constraints.append(
    5843                self.expression(
    5844                    exp.ColumnConstraint,
    5845                    kind=exp.TransformColumnConstraint(this=self._parse_disjunction()),
    5846                )
    5847            )
    5848
    5849        while True:
    5850            constraint = self._parse_column_constraint()
    5851            if not constraint:
    5852                break
    5853            constraints.append(constraint)
    5854
    5855        if not kind and not constraints:
    5856            return this
    5857
    5858        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
    5859
    5860    def _parse_auto_increment(
    5861        self,
    5862    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
    5863        start = None
    5864        increment = None
    5865
    5866        if self._match(TokenType.L_PAREN, advance=False):
    5867            args = self._parse_wrapped_csv(self._parse_bitwise)
    5868            start = seq_get(args, 0)
    5869            increment = seq_get(args, 1)
    5870        elif self._match_text_seq("START"):
    5871            start = self._parse_bitwise()
    5872            self._match_text_seq("INCREMENT")
    5873            increment = self._parse_bitwise()
    5874
    5875        if start and increment:
    5876            return exp.GeneratedAsIdentityColumnConstraint(
    5877                start=start, increment=increment, this=False
    5878            )
    5879
    5880        return exp.AutoIncrementColumnConstraint()
    5881
    5882    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
    5883        if not self._match_text_seq("REFRESH"):
    5884            self._retreat(self._index - 1)
    5885            return None
    5886        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
    5887
    5888    def _parse_compress(self) -> exp.CompressColumnConstraint:
    5889        if self._match(TokenType.L_PAREN, advance=False):
    5890            return self.expression(
    5891                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
    5892            )
    5893
    5894        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
    5895
    5896    def _parse_generated_as_identity(
    5897        self,
    5898    ) -> (
    5899        exp.GeneratedAsIdentityColumnConstraint
    5900        | exp.ComputedColumnConstraint
    5901        | exp.GeneratedAsRowColumnConstraint
    5902    ):
    5903        if self._match_text_seq("BY", "DEFAULT"):
    5904            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
    5905            this = self.expression(
    5906                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
    5907            )
    5908        else:
    5909            self._match_text_seq("ALWAYS")
    5910            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
    5911
    5912        self._match(TokenType.ALIAS)
    5913
    5914        if self._match_text_seq("ROW"):
    5915            start = self._match_text_seq("START")
    5916            if not start:
    5917                self._match(TokenType.END)
    5918            hidden = self._match_text_seq("HIDDEN")
    5919            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
    5920
    5921        identity = self._match_text_seq("IDENTITY")
    5922
    5923        if self._match(TokenType.L_PAREN):
    5924            if self._match(TokenType.START_WITH):
    5925                this.set("start", self._parse_bitwise())
    5926            if self._match_text_seq("INCREMENT", "BY"):
    5927                this.set("increment", self._parse_bitwise())
    5928            if self._match_text_seq("MINVALUE"):
    5929                this.set("minvalue", self._parse_bitwise())
    5930            if self._match_text_seq("MAXVALUE"):
    5931                this.set("maxvalue", self._parse_bitwise())
    5932
    5933            if self._match_text_seq("CYCLE"):
    5934                this.set("cycle", True)
    5935            elif self._match_text_seq("NO", "CYCLE"):
    5936                this.set("cycle", False)
    5937
    5938            if not identity:
    5939                this.set("expression", self._parse_range())
    5940            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
    5941                args = self._parse_csv(self._parse_bitwise)
    5942                this.set("start", seq_get(args, 0))
    5943                this.set("increment", seq_get(args, 1))
    5944
    5945            self._match_r_paren()
    5946
    5947        return this
    5948
    5949    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
    5950        self._match_text_seq("LENGTH")
    5951        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
    5952
    5953    def _parse_not_constraint(self) -> t.Optional[exp.Expression]:
    5954        if self._match_text_seq("NULL"):
    5955            return self.expression(exp.NotNullColumnConstraint)
    5956        if self._match_text_seq("CASESPECIFIC"):
    5957            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
    5958        if self._match_text_seq("FOR", "REPLICATION"):
    5959            return self.expression(exp.NotForReplicationColumnConstraint)
    5960
    5961        # Unconsume the `NOT` token
    5962        self._retreat(self._index - 1)
    5963        return None
    5964
    5965    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
    5966        this = self._match(TokenType.CONSTRAINT) and self._parse_id_var()
    5967
    5968        procedure_option_follows = (
    5969            self._match(TokenType.WITH, advance=False)
    5970            and self._next
    5971            and self._next.text.upper() in self.PROCEDURE_OPTIONS
    5972        )
    5973
    5974        if not procedure_option_follows and self._match_texts(self.CONSTRAINT_PARSERS):
    5975            return self.expression(
    5976                exp.ColumnConstraint,
    5977                this=this,
    5978                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
    5979            )
    5980
    5981        return this
    5982
    5983    def _parse_constraint(self) -> t.Optional[exp.Expression]:
    5984        if not self._match(TokenType.CONSTRAINT):
    5985            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
    5986
    5987        return self.expression(
    5988            exp.Constraint,
    5989            this=self._parse_id_var(),
    5990            expressions=self._parse_unnamed_constraints(),
    5991        )
    5992
    5993    def _parse_unnamed_constraints(self) -> t.List[exp.Expression]:
    5994        constraints = []
    5995        while True:
    5996            constraint = self._parse_unnamed_constraint() or self._parse_function()
    5997            if not constraint:
    5998                break
    5999            constraints.append(constraint)
    6000
    6001        return constraints
    6002
    6003    def _parse_unnamed_constraint(
    6004        self, constraints: t.Optional[t.Collection[str]] = None
    6005    ) -> t.Optional[exp.Expression]:
    6006        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
    6007            constraints or self.CONSTRAINT_PARSERS
    6008        ):
    6009            return None
    6010
    6011        constraint = self._prev.text.upper()
    6012        if constraint not in self.CONSTRAINT_PARSERS:
    6013            self.raise_error(f"No parser found for schema constraint {constraint}.")
    6014
    6015        return self.CONSTRAINT_PARSERS[constraint](self)
    6016
    6017    def _parse_unique_key(self) -> t.Optional[exp.Expression]:
    6018        return self._parse_id_var(any_token=False)
    6019
    6020    def _parse_unique(self) -> exp.UniqueColumnConstraint:
    6021        self._match_text_seq("KEY")
    6022        return self.expression(
    6023            exp.UniqueColumnConstraint,
    6024            nulls=self._match_text_seq("NULLS", "NOT", "DISTINCT"),
    6025            this=self._parse_schema(self._parse_unique_key()),
    6026            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
    6027            on_conflict=self._parse_on_conflict(),
    6028            options=self._parse_key_constraint_options(),
    6029        )
    6030
    6031    def _parse_key_constraint_options(self) -> t.List[str]:
    6032        options = []
    6033        while True:
    6034            if not self._curr:
    6035                break
    6036
    6037            if self._match(TokenType.ON):
    6038                action = None
    6039                on = self._advance_any() and self._prev.text
    6040
    6041                if self._match_text_seq("NO", "ACTION"):
    6042                    action = "NO ACTION"
    6043                elif self._match_text_seq("CASCADE"):
    6044                    action = "CASCADE"
    6045                elif self._match_text_seq("RESTRICT"):
    6046                    action = "RESTRICT"
    6047                elif self._match_pair(TokenType.SET, TokenType.NULL):
    6048                    action = "SET NULL"
    6049                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
    6050                    action = "SET DEFAULT"
    6051                else:
    6052                    self.raise_error("Invalid key constraint")
    6053
    6054                options.append(f"ON {on} {action}")
    6055            else:
    6056                var = self._parse_var_from_options(
    6057                    self.KEY_CONSTRAINT_OPTIONS, raise_unmatched=False
    6058                )
    6059                if not var:
    6060                    break
    6061                options.append(var.name)
    6062
    6063        return options
    6064
    6065    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
    6066        if match and not self._match(TokenType.REFERENCES):
    6067            return None
    6068
    6069        expressions = None
    6070        this = self._parse_table(schema=True)
    6071        options = self._parse_key_constraint_options()
    6072        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
    6073
    6074    def _parse_foreign_key(self) -> exp.ForeignKey:
    6075        expressions = self._parse_wrapped_id_vars()
    6076        reference = self._parse_references()
    6077        on_options = {}
    6078
    6079        while self._match(TokenType.ON):
    6080            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
    6081                self.raise_error("Expected DELETE or UPDATE")
    6082
    6083            kind = self._prev.text.lower()
    6084
    6085            if self._match_text_seq("NO", "ACTION"):
    6086                action = "NO ACTION"
    6087            elif self._match(TokenType.SET):
    6088                self._match_set((TokenType.NULL, TokenType.DEFAULT))
    6089                action = "SET " + self._prev.text.upper()
    6090            else:
    6091                self._advance()
    6092                action = self._prev.text.upper()
    6093
    6094            on_options[kind] = action
    6095
    6096        return self.expression(
    6097            exp.ForeignKey,
    6098            expressions=expressions,
    6099            reference=reference,
    6100            options=self._parse_key_constraint_options(),
    6101            **on_options,  # type: ignore
    6102        )
    6103
    6104    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
    6105        return self._parse_ordered() or self._parse_field()
    6106
    6107    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
    6108        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
    6109            self._retreat(self._index - 1)
    6110            return None
    6111
    6112        id_vars = self._parse_wrapped_id_vars()
    6113        return self.expression(
    6114            exp.PeriodForSystemTimeConstraint,
    6115            this=seq_get(id_vars, 0),
    6116            expression=seq_get(id_vars, 1),
    6117        )
    6118
    6119    def _parse_primary_key(
    6120        self, wrapped_optional: bool = False, in_props: bool = False
    6121    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
    6122        desc = (
    6123            self._match_set((TokenType.ASC, TokenType.DESC))
    6124            and self._prev.token_type == TokenType.DESC
    6125        )
    6126
    6127        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
    6128            return self.expression(
    6129                exp.PrimaryKeyColumnConstraint,
    6130                desc=desc,
    6131                options=self._parse_key_constraint_options(),
    6132            )
    6133
    6134        expressions = self._parse_wrapped_csv(
    6135            self._parse_primary_key_part, optional=wrapped_optional
    6136        )
    6137        options = self._parse_key_constraint_options()
    6138        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
    6139
    6140    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
    6141        return self._parse_slice(self._parse_alias(self._parse_assignment(), explicit=True))
    6142
    6143    def _parse_odbc_datetime_literal(self) -> exp.Expression:
    6144        """
    6145        Parses a datetime column in ODBC format. We parse the column into the corresponding
    6146        types, for example `{d'yyyy-mm-dd'}` will be parsed as a `Date` column, exactly the
    6147        same as we did for `DATE('yyyy-mm-dd')`.
    6148
    6149        Reference:
    6150        https://learn.microsoft.com/en-us/sql/odbc/reference/develop-app/date-time-and-timestamp-literals
    6151        """
    6152        self._match(TokenType.VAR)
    6153        exp_class = self.ODBC_DATETIME_LITERALS[self._prev.text.lower()]
    6154        expression = self.expression(exp_class=exp_class, this=self._parse_string())
    6155        if not self._match(TokenType.R_BRACE):
    6156            self.raise_error("Expected }")
    6157        return expression
    6158
    6159    def _parse_bracket(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
    6160        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
    6161            return this
    6162
    6163        bracket_kind = self._prev.token_type
    6164        if (
    6165            bracket_kind == TokenType.L_BRACE
    6166            and self._curr
    6167            and self._curr.token_type == TokenType.VAR
    6168            and self._curr.text.lower() in self.ODBC_DATETIME_LITERALS
    6169        ):
    6170            return self._parse_odbc_datetime_literal()
    6171
    6172        expressions = self._parse_csv(
    6173            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
    6174        )
    6175
    6176        if bracket_kind == TokenType.L_BRACKET and not self._match(TokenType.R_BRACKET):
    6177            self.raise_error("Expected ]")
    6178        elif bracket_kind == TokenType.L_BRACE and not self._match(TokenType.R_BRACE):
    6179            self.raise_error("Expected }")
    6180
    6181        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
    6182        if bracket_kind == TokenType.L_BRACE:
    6183            this = self.expression(exp.Struct, expressions=self._kv_to_prop_eq(expressions))
    6184        elif not this:
    6185            this = build_array_constructor(
    6186                exp.Array, args=expressions, bracket_kind=bracket_kind, dialect=self.dialect
    6187            )
    6188        else:
    6189            constructor_type = self.ARRAY_CONSTRUCTORS.get(this.name.upper())
    6190            if constructor_type:
    6191                return build_array_constructor(
    6192                    constructor_type,
    6193                    args=expressions,
    6194                    bracket_kind=bracket_kind,
    6195                    dialect=self.dialect,
    6196                )
    6197
    6198            expressions = apply_index_offset(
    6199                this, expressions, -self.dialect.INDEX_OFFSET, dialect=self.dialect
    6200            )
    6201            this = self.expression(exp.Bracket, this=this, expressions=expressions)
    6202
    6203        self._add_comments(this)
    6204        return self._parse_bracket(this)
    6205
    6206    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    6207        if self._match(TokenType.COLON):
    6208            return self.expression(exp.Slice, this=this, expression=self._parse_assignment())
    6209        return this
    6210
    6211    def _parse_case(self) -> t.Optional[exp.Expression]:
    6212        ifs = []
    6213        default = None
    6214
    6215        comments = self._prev_comments
    6216        expression = self._parse_assignment()
    6217
    6218        while self._match(TokenType.WHEN):
    6219            this = self._parse_assignment()
    6220            self._match(TokenType.THEN)
    6221            then = self._parse_assignment()
    6222            ifs.append(self.expression(exp.If, this=this, true=then))
    6223
    6224        if self._match(TokenType.ELSE):
    6225            default = self._parse_assignment()
    6226
    6227        if not self._match(TokenType.END):
    6228            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
    6229                default = exp.column("interval")
    6230            else:
    6231                self.raise_error("Expected END after CASE", self._prev)
    6232
    6233        return self.expression(
    6234            exp.Case, comments=comments, this=expression, ifs=ifs, default=default
    6235        )
    6236
    6237    def _parse_if(self) -> t.Optional[exp.Expression]:
    6238        if self._match(TokenType.L_PAREN):
    6239            args = self._parse_csv(
    6240                lambda: self._parse_alias(self._parse_assignment(), explicit=True)
    6241            )
    6242            this = self.validate_expression(exp.If.from_arg_list(args), args)
    6243            self._match_r_paren()
    6244        else:
    6245            index = self._index - 1
    6246
    6247            if self.NO_PAREN_IF_COMMANDS and index == 0:
    6248                return self._parse_as_command(self._prev)
    6249
    6250            condition = self._parse_assignment()
    6251
    6252            if not condition:
    6253                self._retreat(index)
    6254                return None
    6255
    6256            self._match(TokenType.THEN)
    6257            true = self._parse_assignment()
    6258            false = self._parse_assignment() if self._match(TokenType.ELSE) else None
    6259            self._match(TokenType.END)
    6260            this = self.expression(exp.If, this=condition, true=true, false=false)
    6261
    6262        return this
    6263
    6264    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
    6265        if not self._match_text_seq("VALUE", "FOR"):
    6266            self._retreat(self._index - 1)
    6267            return None
    6268
    6269        return self.expression(
    6270            exp.NextValueFor,
    6271            this=self._parse_column(),
    6272            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
    6273        )
    6274
    6275    def _parse_extract(self) -> exp.Extract | exp.Anonymous:
    6276        this = self._parse_function() or self._parse_var_or_string(upper=True)
    6277
    6278        if self._match(TokenType.FROM):
    6279            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
    6280
    6281        if not self._match(TokenType.COMMA):
    6282            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
    6283
    6284        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
    6285
    6286    def _parse_gap_fill(self) -> exp.GapFill:
    6287        self._match(TokenType.TABLE)
    6288        this = self._parse_table()
    6289
    6290        self._match(TokenType.COMMA)
    6291        args = [this, *self._parse_csv(self._parse_lambda)]
    6292
    6293        gap_fill = exp.GapFill.from_arg_list(args)
    6294        return self.validate_expression(gap_fill, args)
    6295
    6296    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
    6297        this = self._parse_assignment()
    6298
    6299        if not self._match(TokenType.ALIAS):
    6300            if self._match(TokenType.COMMA):
    6301                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
    6302
    6303            self.raise_error("Expected AS after CAST")
    6304
    6305        fmt = None
    6306        to = self._parse_types()
    6307
    6308        default = self._match(TokenType.DEFAULT)
    6309        if default:
    6310            default = self._parse_bitwise()
    6311            self._match_text_seq("ON", "CONVERSION", "ERROR")
    6312
    6313        if self._match_set((TokenType.FORMAT, TokenType.COMMA)):
    6314            fmt_string = self._parse_string()
    6315            fmt = self._parse_at_time_zone(fmt_string)
    6316
    6317            if not to:
    6318                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
    6319            if to.this in exp.DataType.TEMPORAL_TYPES:
    6320                this = self.expression(
    6321                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
    6322                    this=this,
    6323                    format=exp.Literal.string(
    6324                        format_time(
    6325                            fmt_string.this if fmt_string else "",
    6326                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
    6327                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
    6328                        )
    6329                    ),
    6330                    safe=safe,
    6331                )
    6332
    6333                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
    6334                    this.set("zone", fmt.args["zone"])
    6335                return this
    6336        elif not to:
    6337            self.raise_error("Expected TYPE after CAST")
    6338        elif isinstance(to, exp.Identifier):
    6339            to = exp.DataType.build(to.name, udt=True)
    6340        elif to.this == exp.DataType.Type.CHAR:
    6341            if self._match(TokenType.CHARACTER_SET):
    6342                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
    6343
    6344        return self.expression(
    6345            exp.Cast if strict else exp.TryCast,
    6346            this=this,
    6347            to=to,
    6348            format=fmt,
    6349            safe=safe,
    6350            action=self._parse_var_from_options(self.CAST_ACTIONS, raise_unmatched=False),
    6351            default=default,
    6352        )
    6353
    6354    def _parse_string_agg(self) -> exp.GroupConcat:
    6355        if self._match(TokenType.DISTINCT):
    6356            args: t.List[t.Optional[exp.Expression]] = [
    6357                self.expression(exp.Distinct, expressions=[self._parse_assignment()])
    6358            ]
    6359            if self._match(TokenType.COMMA):
    6360                args.extend(self._parse_csv(self._parse_assignment))
    6361        else:
    6362            args = self._parse_csv(self._parse_assignment)  # type: ignore
    6363
    6364        if self._match_text_seq("ON", "OVERFLOW"):
    6365            # trino: LISTAGG(expression [, separator] [ON OVERFLOW overflow_behavior])
    6366            if self._match_text_seq("ERROR"):
    6367                on_overflow: t.Optional[exp.Expression] = exp.var("ERROR")
    6368            else:
    6369                self._match_text_seq("TRUNCATE")
    6370                on_overflow = self.expression(
    6371                    exp.OverflowTruncateBehavior,
    6372                    this=self._parse_string(),
    6373                    with_count=(
    6374                        self._match_text_seq("WITH", "COUNT")
    6375                        or not self._match_text_seq("WITHOUT", "COUNT")
    6376                    ),
    6377                )
    6378        else:
    6379            on_overflow = None
    6380
    6381        index = self._index
    6382        if not self._match(TokenType.R_PAREN) and args:
    6383            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
    6384            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
    6385            # The order is parsed through `this` as a canonicalization for WITHIN GROUPs
    6386            args[0] = self._parse_limit(this=self._parse_order(this=args[0]))
    6387            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
    6388
    6389        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
    6390        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
    6391        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
    6392        if not self._match_text_seq("WITHIN", "GROUP"):
    6393            self._retreat(index)
    6394            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
    6395
    6396        # The corresponding match_r_paren will be called in parse_function (caller)
    6397        self._match_l_paren()
    6398
    6399        return self.expression(
    6400            exp.GroupConcat,
    6401            this=self._parse_order(this=seq_get(args, 0)),
    6402            separator=seq_get(args, 1),
    6403            on_overflow=on_overflow,
    6404        )
    6405
    6406    def _parse_convert(
    6407        self, strict: bool, safe: t.Optional[bool] = None
    6408    ) -> t.Optional[exp.Expression]:
    6409        this = self._parse_bitwise()
    6410
    6411        if self._match(TokenType.USING):
    6412            to: t.Optional[exp.Expression] = self.expression(
    6413                exp.CharacterSet, this=self._parse_var()
    6414            )
    6415        elif self._match(TokenType.COMMA):
    6416            to = self._parse_types()
    6417        else:
    6418            to = None
    6419
    6420        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
    6421
    6422    def _parse_xml_table(self) -> exp.XMLTable:
    6423        namespaces = None
    6424        passing = None
    6425        columns = None
    6426
    6427        if self._match_text_seq("XMLNAMESPACES", "("):
    6428            namespaces = self._parse_xml_namespace()
    6429            self._match_text_seq(")", ",")
    6430
    6431        this = self._parse_string()
    6432
    6433        if self._match_text_seq("PASSING"):
    6434            # The BY VALUE keywords are optional and are provided for semantic clarity
    6435            self._match_text_seq("BY", "VALUE")
    6436            passing = self._parse_csv(self._parse_column)
    6437
    6438        by_ref = self._match_text_seq("RETURNING", "SEQUENCE", "BY", "REF")
    6439
    6440        if self._match_text_seq("COLUMNS"):
    6441            columns = self._parse_csv(self._parse_field_def)
    6442
    6443        return self.expression(
    6444            exp.XMLTable,
    6445            this=this,
    6446            namespaces=namespaces,
    6447            passing=passing,
    6448            columns=columns,
    6449            by_ref=by_ref,
    6450        )
    6451
    6452    def _parse_xml_namespace(self) -> t.List[exp.XMLNamespace]:
    6453        namespaces = []
    6454
    6455        while True:
    6456            if self._match(TokenType.DEFAULT):
    6457                uri = self._parse_string()
    6458            else:
    6459                uri = self._parse_alias(self._parse_string())
    6460            namespaces.append(self.expression(exp.XMLNamespace, this=uri))
    6461            if not self._match(TokenType.COMMA):
    6462                break
    6463
    6464        return namespaces
    6465
    6466    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
    6467        """
    6468        There are generally two variants of the DECODE function:
    6469
    6470        - DECODE(bin, charset)
    6471        - DECODE(expression, search, result [, search, result] ... [, default])
    6472
    6473        The second variant will always be parsed into a CASE expression. Note that NULL
    6474        needs special treatment, since we need to explicitly check for it with `IS NULL`,
    6475        instead of relying on pattern matching.
    6476        """
    6477        args = self._parse_csv(self._parse_assignment)
    6478
    6479        if len(args) < 3:
    6480            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
    6481
    6482        expression, *expressions = args
    6483        if not expression:
    6484            return None
    6485
    6486        ifs = []
    6487        for search, result in zip(expressions[::2], expressions[1::2]):
    6488            if not search or not result:
    6489                return None
    6490
    6491            if isinstance(search, exp.Literal):
    6492                ifs.append(
    6493                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
    6494                )
    6495            elif isinstance(search, exp.Null):
    6496                ifs.append(
    6497                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
    6498                )
    6499            else:
    6500                cond = exp.or_(
    6501                    exp.EQ(this=expression.copy(), expression=search),
    6502                    exp.and_(
    6503                        exp.Is(this=expression.copy(), expression=exp.Null()),
    6504                        exp.Is(this=search.copy(), expression=exp.Null()),
    6505                        copy=False,
    6506                    ),
    6507                    copy=False,
    6508                )
    6509                ifs.append(exp.If(this=cond, true=result))
    6510
    6511        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
    6512
    6513    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
    6514        self._match_text_seq("KEY")
    6515        key = self._parse_column()
    6516        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
    6517        self._match_text_seq("VALUE")
    6518        value = self._parse_bitwise()
    6519
    6520        if not key and not value:
    6521            return None
    6522        return self.expression(exp.JSONKeyValue, this=key, expression=value)
    6523
    6524    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    6525        if not this or not self._match_text_seq("FORMAT", "JSON"):
    6526            return this
    6527
    6528        return self.expression(exp.FormatJson, this=this)
    6529
    6530    def _parse_on_condition(self) -> t.Optional[exp.OnCondition]:
    6531        # MySQL uses "X ON EMPTY Y ON ERROR" (e.g. JSON_VALUE) while Oracle uses the opposite (e.g. JSON_EXISTS)
    6532        if self.dialect.ON_CONDITION_EMPTY_BEFORE_ERROR:
    6533            empty = self._parse_on_handling("EMPTY", *self.ON_CONDITION_TOKENS)
    6534            error = self._parse_on_handling("ERROR", *self.ON_CONDITION_TOKENS)
    6535        else:
    6536            error = self._parse_on_handling("ERROR", *self.ON_CONDITION_TOKENS)
    6537            empty = self._parse_on_handling("EMPTY", *self.ON_CONDITION_TOKENS)
    6538
    6539        null = self._parse_on_handling("NULL", *self.ON_CONDITION_TOKENS)
    6540
    6541        if not empty and not error and not null:
    6542            return None
    6543
    6544        return self.expression(
    6545            exp.OnCondition,
    6546            empty=empty,
    6547            error=error,
    6548            null=null,
    6549        )
    6550
    6551    def _parse_on_handling(
    6552        self, on: str, *values: str
    6553    ) -> t.Optional[str] | t.Optional[exp.Expression]:
    6554        # Parses the "X ON Y" or "DEFAULT <expr> ON Y syntax, e.g. NULL ON NULL (Oracle, T-SQL, MySQL)
    6555        for value in values:
    6556            if self._match_text_seq(value, "ON", on):
    6557                return f"{value} ON {on}"
    6558
    6559        index = self._index
    6560        if self._match(TokenType.DEFAULT):
    6561            default_value = self._parse_bitwise()
    6562            if self._match_text_seq("ON", on):
    6563                return default_value
    6564
    6565            self._retreat(index)
    6566
    6567        return None
    6568
    6569    @t.overload
    6570    def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
    6571
    6572    @t.overload
    6573    def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
    6574
    6575    def _parse_json_object(self, agg=False):
    6576        star = self._parse_star()
    6577        expressions = (
    6578            [star]
    6579            if star
    6580            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
    6581        )
    6582        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
    6583
    6584        unique_keys = None
    6585        if self._match_text_seq("WITH", "UNIQUE"):
    6586            unique_keys = True
    6587        elif self._match_text_seq("WITHOUT", "UNIQUE"):
    6588            unique_keys = False
    6589
    6590        self._match_text_seq("KEYS")
    6591
    6592        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
    6593            self._parse_type()
    6594        )
    6595        encoding = self._match_text_seq("ENCODING") and self._parse_var()
    6596
    6597        return self.expression(
    6598            exp.JSONObjectAgg if agg else exp.JSONObject,
    6599            expressions=expressions,
    6600            null_handling=null_handling,
    6601            unique_keys=unique_keys,
    6602            return_type=return_type,
    6603            encoding=encoding,
    6604        )
    6605
    6606    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
    6607    def _parse_json_column_def(self) -> exp.JSONColumnDef:
    6608        if not self._match_text_seq("NESTED"):
    6609            this = self._parse_id_var()
    6610            kind = self._parse_types(allow_identifiers=False)
    6611            nested = None
    6612        else:
    6613            this = None
    6614            kind = None
    6615            nested = True
    6616
    6617        path = self._match_text_seq("PATH") and self._parse_string()
    6618        nested_schema = nested and self._parse_json_schema()
    6619
    6620        return self.expression(
    6621            exp.JSONColumnDef,
    6622            this=this,
    6623            kind=kind,
    6624            path=path,
    6625            nested_schema=nested_schema,
    6626        )
    6627
    6628    def _parse_json_schema(self) -> exp.JSONSchema:
    6629        self._match_text_seq("COLUMNS")
    6630        return self.expression(
    6631            exp.JSONSchema,
    6632            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
    6633        )
    6634
    6635    def _parse_json_table(self) -> exp.JSONTable:
    6636        this = self._parse_format_json(self._parse_bitwise())
    6637        path = self._match(TokenType.COMMA) and self._parse_string()
    6638        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
    6639        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
    6640        schema = self._parse_json_schema()
    6641
    6642        return exp.JSONTable(
    6643            this=this,
    6644            schema=schema,
    6645            path=path,
    6646            error_handling=error_handling,
    6647            empty_handling=empty_handling,
    6648        )
    6649
    6650    def _parse_match_against(self) -> exp.MatchAgainst:
    6651        expressions = self._parse_csv(self._parse_column)
    6652
    6653        self._match_text_seq(")", "AGAINST", "(")
    6654
    6655        this = self._parse_string()
    6656
    6657        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
    6658            modifier = "IN NATURAL LANGUAGE MODE"
    6659            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
    6660                modifier = f"{modifier} WITH QUERY EXPANSION"
    6661        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
    6662            modifier = "IN BOOLEAN MODE"
    6663        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
    6664            modifier = "WITH QUERY EXPANSION"
    6665        else:
    6666            modifier = None
    6667
    6668        return self.expression(
    6669            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
    6670        )
    6671
    6672    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
    6673    def _parse_open_json(self) -> exp.OpenJSON:
    6674        this = self._parse_bitwise()
    6675        path = self._match(TokenType.COMMA) and self._parse_string()
    6676
    6677        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
    6678            this = self._parse_field(any_token=True)
    6679            kind = self._parse_types()
    6680            path = self._parse_string()
    6681            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
    6682
    6683            return self.expression(
    6684                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
    6685            )
    6686
    6687        expressions = None
    6688        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
    6689            self._match_l_paren()
    6690            expressions = self._parse_csv(_parse_open_json_column_def)
    6691
    6692        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
    6693
    6694    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
    6695        args = self._parse_csv(self._parse_bitwise)
    6696
    6697        if self._match(TokenType.IN):
    6698            return self.expression(
    6699                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
    6700            )
    6701
    6702        if haystack_first:
    6703            haystack = seq_get(args, 0)
    6704            needle = seq_get(args, 1)
    6705        else:
    6706            haystack = seq_get(args, 1)
    6707            needle = seq_get(args, 0)
    6708
    6709        return self.expression(
    6710            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
    6711        )
    6712
    6713    def _parse_predict(self) -> exp.Predict:
    6714        self._match_text_seq("MODEL")
    6715        this = self._parse_table()
    6716
    6717        self._match(TokenType.COMMA)
    6718        self._match_text_seq("TABLE")
    6719
    6720        return self.expression(
    6721            exp.Predict,
    6722            this=this,
    6723            expression=self._parse_table(),
    6724            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
    6725        )
    6726
    6727    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
    6728        args = self._parse_csv(self._parse_table)
    6729        return exp.JoinHint(this=func_name.upper(), expressions=args)
    6730
    6731    def _parse_substring(self) -> exp.Substring:
    6732        # Postgres supports the form: substring(string [from int] [for int])
    6733        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
    6734
    6735        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
    6736
    6737        if self._match(TokenType.FROM):
    6738            args.append(self._parse_bitwise())
    6739        if self._match(TokenType.FOR):
    6740            if len(args) == 1:
    6741                args.append(exp.Literal.number(1))
    6742            args.append(self._parse_bitwise())
    6743
    6744        return self.validate_expression(exp.Substring.from_arg_list(args), args)
    6745
    6746    def _parse_trim(self) -> exp.Trim:
    6747        # https://www.w3resource.com/sql/character-functions/trim.php
    6748        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
    6749
    6750        position = None
    6751        collation = None
    6752        expression = None
    6753
    6754        if self._match_texts(self.TRIM_TYPES):
    6755            position = self._prev.text.upper()
    6756
    6757        this = self._parse_bitwise()
    6758        if self._match_set((TokenType.FROM, TokenType.COMMA)):
    6759            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
    6760            expression = self._parse_bitwise()
    6761
    6762            if invert_order:
    6763                this, expression = expression, this
    6764
    6765        if self._match(TokenType.COLLATE):
    6766            collation = self._parse_bitwise()
    6767
    6768        return self.expression(
    6769            exp.Trim, this=this, position=position, expression=expression, collation=collation
    6770        )
    6771
    6772    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
    6773        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
    6774
    6775    def _parse_named_window(self) -> t.Optional[exp.Expression]:
    6776        return self._parse_window(self._parse_id_var(), alias=True)
    6777
    6778    def _parse_respect_or_ignore_nulls(
    6779        self, this: t.Optional[exp.Expression]
    6780    ) -> t.Optional[exp.Expression]:
    6781        if self._match_text_seq("IGNORE", "NULLS"):
    6782            return self.expression(exp.IgnoreNulls, this=this)
    6783        if self._match_text_seq("RESPECT", "NULLS"):
    6784            return self.expression(exp.RespectNulls, this=this)
    6785        return this
    6786
    6787    def _parse_having_max(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    6788        if self._match(TokenType.HAVING):
    6789            self._match_texts(("MAX", "MIN"))
    6790            max = self._prev.text.upper() != "MIN"
    6791            return self.expression(
    6792                exp.HavingMax, this=this, expression=self._parse_column(), max=max
    6793            )
    6794
    6795        return this
    6796
    6797    def _parse_window(
    6798        self, this: t.Optional[exp.Expression], alias: bool = False
    6799    ) -> t.Optional[exp.Expression]:
    6800        func = this
    6801        comments = func.comments if isinstance(func, exp.Expression) else None
    6802
    6803        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
    6804        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
    6805        if self._match_text_seq("WITHIN", "GROUP"):
    6806            order = self._parse_wrapped(self._parse_order)
    6807            this = self.expression(exp.WithinGroup, this=this, expression=order)
    6808
    6809        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
    6810            self._match(TokenType.WHERE)
    6811            this = self.expression(
    6812                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
    6813            )
    6814            self._match_r_paren()
    6815
    6816        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
    6817        # Some dialects choose to implement and some do not.
    6818        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
    6819
    6820        # There is some code above in _parse_lambda that handles
    6821        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
    6822
    6823        # The below changes handle
    6824        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
    6825
    6826        # Oracle allows both formats
    6827        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
    6828        #   and Snowflake chose to do the same for familiarity
    6829        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
    6830        if isinstance(this, exp.AggFunc):
    6831            ignore_respect = this.find(exp.IgnoreNulls, exp.RespectNulls)
    6832
    6833            if ignore_respect and ignore_respect is not this:
    6834                ignore_respect.replace(ignore_respect.this)
    6835                this = self.expression(ignore_respect.__class__, this=this)
    6836
    6837        this = self._parse_respect_or_ignore_nulls(this)
    6838
    6839        # bigquery select from window x AS (partition by ...)
    6840        if alias:
    6841            over = None
    6842            self._match(TokenType.ALIAS)
    6843        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
    6844            return this
    6845        else:
    6846            over = self._prev.text.upper()
    6847
    6848        if comments and isinstance(func, exp.Expression):
    6849            func.pop_comments()
    6850
    6851        if not self._match(TokenType.L_PAREN):
    6852            return self.expression(
    6853                exp.Window,
    6854                comments=comments,
    6855                this=this,
    6856                alias=self._parse_id_var(False),
    6857                over=over,
    6858            )
    6859
    6860        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
    6861
    6862        first = self._match(TokenType.FIRST)
    6863        if self._match_text_seq("LAST"):
    6864            first = False
    6865
    6866        partition, order = self._parse_partition_and_order()
    6867        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
    6868
    6869        if kind:
    6870            self._match(TokenType.BETWEEN)
    6871            start = self._parse_window_spec()
    6872            self._match(TokenType.AND)
    6873            end = self._parse_window_spec()
    6874
    6875            spec = self.expression(
    6876                exp.WindowSpec,
    6877                kind=kind,
    6878                start=start["value"],
    6879                start_side=start["side"],
    6880                end=end["value"],
    6881                end_side=end["side"],
    6882            )
    6883        else:
    6884            spec = None
    6885
    6886        self._match_r_paren()
    6887
    6888        window = self.expression(
    6889            exp.Window,
    6890            comments=comments,
    6891            this=this,
    6892            partition_by=partition,
    6893            order=order,
    6894            spec=spec,
    6895            alias=window_alias,
    6896            over=over,
    6897            first=first,
    6898        )
    6899
    6900        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
    6901        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
    6902            return self._parse_window(window, alias=alias)
    6903
    6904        return window
    6905
    6906    def _parse_partition_and_order(
    6907        self,
    6908    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
    6909        return self._parse_partition_by(), self._parse_order()
    6910
    6911    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
    6912        self._match(TokenType.BETWEEN)
    6913
    6914        return {
    6915            "value": (
    6916                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
    6917                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
    6918                or self._parse_bitwise()
    6919            ),
    6920            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
    6921        }
    6922
    6923    def _parse_alias(
    6924        self, this: t.Optional[exp.Expression], explicit: bool = False
    6925    ) -> t.Optional[exp.Expression]:
    6926        # In some dialects, LIMIT and OFFSET can act as both identifiers and keywords (clauses)
    6927        # so this section tries to parse the clause version and if it fails, it treats the token
    6928        # as an identifier (alias)
    6929        if self._can_parse_limit_or_offset():
    6930            return this
    6931
    6932        any_token = self._match(TokenType.ALIAS)
    6933        comments = self._prev_comments or []
    6934
    6935        if explicit and not any_token:
    6936            return this
    6937
    6938        if self._match(TokenType.L_PAREN):
    6939            aliases = self.expression(
    6940                exp.Aliases,
    6941                comments=comments,
    6942                this=this,
    6943                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
    6944            )
    6945            self._match_r_paren(aliases)
    6946            return aliases
    6947
    6948        alias = self._parse_id_var(any_token, tokens=self.ALIAS_TOKENS) or (
    6949            self.STRING_ALIASES and self._parse_string_as_identifier()
    6950        )
    6951
    6952        if alias:
    6953            comments.extend(alias.pop_comments())
    6954            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
    6955            column = this.this
    6956
    6957            # Moves the comment next to the alias in `expr /* comment */ AS alias`
    6958            if not this.comments and column and column.comments:
    6959                this.comments = column.pop_comments()
    6960
    6961        return this
    6962
    6963    def _parse_id_var(
    6964        self,
    6965        any_token: bool = True,
    6966        tokens: t.Optional[t.Collection[TokenType]] = None,
    6967    ) -> t.Optional[exp.Expression]:
    6968        expression = self._parse_identifier()
    6969        if not expression and (
    6970            (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS)
    6971        ):
    6972            quoted = self._prev.token_type == TokenType.STRING
    6973            expression = self.expression(exp.Identifier, this=self._prev.text, quoted=quoted)
    6974
    6975        return expression
    6976
    6977    def _parse_string(self) -> t.Optional[exp.Expression]:
    6978        if self._match_set(self.STRING_PARSERS):
    6979            return self.STRING_PARSERS[self._prev.token_type](self, self._prev)
    6980        return self._parse_placeholder()
    6981
    6982    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
    6983        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
    6984
    6985    def _parse_number(self) -> t.Optional[exp.Expression]:
    6986        if self._match_set(self.NUMERIC_PARSERS):
    6987            return self.NUMERIC_PARSERS[self._prev.token_type](self, self._prev)
    6988        return self._parse_placeholder()
    6989
    6990    def _parse_identifier(self) -> t.Optional[exp.Expression]:
    6991        if self._match(TokenType.IDENTIFIER):
    6992            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
    6993        return self._parse_placeholder()
    6994
    6995    def _parse_var(
    6996        self,
    6997        any_token: bool = False,
    6998        tokens: t.Optional[t.Collection[TokenType]] = None,
    6999        upper: bool = False,
    7000    ) -> t.Optional[exp.Expression]:
    7001        if (
    7002            (any_token and self._advance_any())
    7003            or self._match(TokenType.VAR)
    7004            or (self._match_set(tokens) if tokens else False)
    7005        ):
    7006            return self.expression(
    7007                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
    7008            )
    7009        return self._parse_placeholder()
    7010
    7011    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
    7012        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
    7013            self._advance()
    7014            return self._prev
    7015        return None
    7016
    7017    def _parse_var_or_string(self, upper: bool = False) -> t.Optional[exp.Expression]:
    7018        return self._parse_string() or self._parse_var(any_token=True, upper=upper)
    7019
    7020    def _parse_primary_or_var(self) -> t.Optional[exp.Expression]:
    7021        return self._parse_primary() or self._parse_var(any_token=True)
    7022
    7023    def _parse_null(self) -> t.Optional[exp.Expression]:
    7024        if self._match_set(self.NULL_TOKENS):
    7025            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
    7026        return self._parse_placeholder()
    7027
    7028    def _parse_boolean(self) -> t.Optional[exp.Expression]:
    7029        if self._match(TokenType.TRUE):
    7030            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
    7031        if self._match(TokenType.FALSE):
    7032            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
    7033        return self._parse_placeholder()
    7034
    7035    def _parse_star(self) -> t.Optional[exp.Expression]:
    7036        if self._match(TokenType.STAR):
    7037            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
    7038        return self._parse_placeholder()
    7039
    7040    def _parse_parameter(self) -> exp.Parameter:
    7041        this = self._parse_identifier() or self._parse_primary_or_var()
    7042        return self.expression(exp.Parameter, this=this)
    7043
    7044    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
    7045        if self._match_set(self.PLACEHOLDER_PARSERS):
    7046            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
    7047            if placeholder:
    7048                return placeholder
    7049            self._advance(-1)
    7050        return None
    7051
    7052    def _parse_star_op(self, *keywords: str) -> t.Optional[t.List[exp.Expression]]:
    7053        if not self._match_texts(keywords):
    7054            return None
    7055        if self._match(TokenType.L_PAREN, advance=False):
    7056            return self._parse_wrapped_csv(self._parse_expression)
    7057
    7058        expression = self._parse_expression()
    7059        return [expression] if expression else None
    7060
    7061    def _parse_csv(
    7062        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
    7063    ) -> t.List[exp.Expression]:
    7064        parse_result = parse_method()
    7065        items = [parse_result] if parse_result is not None else []
    7066
    7067        while self._match(sep):
    7068            self._add_comments(parse_result)
    7069            parse_result = parse_method()
    7070            if parse_result is not None:
    7071                items.append(parse_result)
    7072
    7073        return items
    7074
    7075    def _parse_tokens(
    7076        self, parse_method: t.Callable, expressions: t.Dict
    7077    ) -> t.Optional[exp.Expression]:
    7078        this = parse_method()
    7079
    7080        while self._match_set(expressions):
    7081            this = self.expression(
    7082                expressions[self._prev.token_type],
    7083                this=this,
    7084                comments=self._prev_comments,
    7085                expression=parse_method(),
    7086            )
    7087
    7088        return this
    7089
    7090    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
    7091        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
    7092
    7093    def _parse_wrapped_csv(
    7094        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
    7095    ) -> t.List[exp.Expression]:
    7096        return self._parse_wrapped(
    7097            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
    7098        )
    7099
    7100    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
    7101        wrapped = self._match(TokenType.L_PAREN)
    7102        if not wrapped and not optional:
    7103            self.raise_error("Expecting (")
    7104        parse_result = parse_method()
    7105        if wrapped:
    7106            self._match_r_paren()
    7107        return parse_result
    7108
    7109    def _parse_expressions(self) -> t.List[exp.Expression]:
    7110        return self._parse_csv(self._parse_expression)
    7111
    7112    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
    7113        return self._parse_select() or self._parse_set_operations(
    7114            self._parse_alias(self._parse_assignment(), explicit=True)
    7115            if alias
    7116            else self._parse_assignment()
    7117        )
    7118
    7119    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
    7120        return self._parse_query_modifiers(
    7121            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
    7122        )
    7123
    7124    def _parse_transaction(self) -> exp.Transaction | exp.Command:
    7125        this = None
    7126        if self._match_texts(self.TRANSACTION_KIND):
    7127            this = self._prev.text
    7128
    7129        self._match_texts(("TRANSACTION", "WORK"))
    7130
    7131        modes = []
    7132        while True:
    7133            mode = []
    7134            while self._match(TokenType.VAR):
    7135                mode.append(self._prev.text)
    7136
    7137            if mode:
    7138                modes.append(" ".join(mode))
    7139            if not self._match(TokenType.COMMA):
    7140                break
    7141
    7142        return self.expression(exp.Transaction, this=this, modes=modes)
    7143
    7144    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
    7145        chain = None
    7146        savepoint = None
    7147        is_rollback = self._prev.token_type == TokenType.ROLLBACK
    7148
    7149        self._match_texts(("TRANSACTION", "WORK"))
    7150
    7151        if self._match_text_seq("TO"):
    7152            self._match_text_seq("SAVEPOINT")
    7153            savepoint = self._parse_id_var()
    7154
    7155        if self._match(TokenType.AND):
    7156            chain = not self._match_text_seq("NO")
    7157            self._match_text_seq("CHAIN")
    7158
    7159        if is_rollback:
    7160            return self.expression(exp.Rollback, savepoint=savepoint)
    7161
    7162        return self.expression(exp.Commit, chain=chain)
    7163
    7164    def _parse_refresh(self) -> exp.Refresh:
    7165        self._match(TokenType.TABLE)
    7166        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
    7167
    7168    def _parse_add_column(self) -> t.Optional[exp.Expression]:
    7169        if not self._match_text_seq("ADD"):
    7170            return None
    7171
    7172        self._match(TokenType.COLUMN)
    7173        exists_column = self._parse_exists(not_=True)
    7174        expression = self._parse_field_def()
    7175
    7176        if expression:
    7177            expression.set("exists", exists_column)
    7178
    7179            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
    7180            if self._match_texts(("FIRST", "AFTER")):
    7181                position = self._prev.text
    7182                column_position = self.expression(
    7183                    exp.ColumnPosition, this=self._parse_column(), position=position
    7184                )
    7185                expression.set("position", column_position)
    7186
    7187        return expression
    7188
    7189    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
    7190        drop = self._match(TokenType.DROP) and self._parse_drop()
    7191        if drop and not isinstance(drop, exp.Command):
    7192            drop.set("kind", drop.args.get("kind", "COLUMN"))
    7193        return drop
    7194
    7195    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
    7196    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
    7197        return self.expression(
    7198            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
    7199        )
    7200
    7201    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
    7202        index = self._index - 1
    7203
    7204        if self._match_set(self.ADD_CONSTRAINT_TOKENS, advance=False):
    7205            return self._parse_csv(
    7206                lambda: self.expression(
    7207                    exp.AddConstraint, expressions=self._parse_csv(self._parse_constraint)
    7208                )
    7209            )
    7210
    7211        self._retreat(index)
    7212        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
    7213            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
    7214
    7215        if self._match_text_seq("ADD", "COLUMNS"):
    7216            schema = self._parse_schema()
    7217            if schema:
    7218                return [schema]
    7219            return []
    7220
    7221        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
    7222
    7223    def _parse_alter_table_alter(self) -> t.Optional[exp.Expression]:
    7224        if self._match_texts(self.ALTER_ALTER_PARSERS):
    7225            return self.ALTER_ALTER_PARSERS[self._prev.text.upper()](self)
    7226
    7227        # Many dialects support the ALTER [COLUMN] syntax, so if there is no
    7228        # keyword after ALTER we default to parsing this statement
    7229        self._match(TokenType.COLUMN)
    7230        column = self._parse_field(any_token=True)
    7231
    7232        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
    7233            return self.expression(exp.AlterColumn, this=column, drop=True)
    7234        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
    7235            return self.expression(exp.AlterColumn, this=column, default=self._parse_assignment())
    7236        if self._match(TokenType.COMMENT):
    7237            return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
    7238        if self._match_text_seq("DROP", "NOT", "NULL"):
    7239            return self.expression(
    7240                exp.AlterColumn,
    7241                this=column,
    7242                drop=True,
    7243                allow_null=True,
    7244            )
    7245        if self._match_text_seq("SET", "NOT", "NULL"):
    7246            return self.expression(
    7247                exp.AlterColumn,
    7248                this=column,
    7249                allow_null=False,
    7250            )
    7251
    7252        if self._match_text_seq("SET", "VISIBLE"):
    7253            return self.expression(exp.AlterColumn, this=column, visible="VISIBLE")
    7254        if self._match_text_seq("SET", "INVISIBLE"):
    7255            return self.expression(exp.AlterColumn, this=column, visible="INVISIBLE")
    7256
    7257        self._match_text_seq("SET", "DATA")
    7258        self._match_text_seq("TYPE")
    7259        return self.expression(
    7260            exp.AlterColumn,
    7261            this=column,
    7262            dtype=self._parse_types(),
    7263            collate=self._match(TokenType.COLLATE) and self._parse_term(),
    7264            using=self._match(TokenType.USING) and self._parse_assignment(),
    7265        )
    7266
    7267    def _parse_alter_diststyle(self) -> exp.AlterDistStyle:
    7268        if self._match_texts(("ALL", "EVEN", "AUTO")):
    7269            return self.expression(exp.AlterDistStyle, this=exp.var(self._prev.text.upper()))
    7270
    7271        self._match_text_seq("KEY", "DISTKEY")
    7272        return self.expression(exp.AlterDistStyle, this=self._parse_column())
    7273
    7274    def _parse_alter_sortkey(self, compound: t.Optional[bool] = None) -> exp.AlterSortKey:
    7275        if compound:
    7276            self._match_text_seq("SORTKEY")
    7277
    7278        if self._match(TokenType.L_PAREN, advance=False):
    7279            return self.expression(
    7280                exp.AlterSortKey, expressions=self._parse_wrapped_id_vars(), compound=compound
    7281            )
    7282
    7283        self._match_texts(("AUTO", "NONE"))
    7284        return self.expression(
    7285            exp.AlterSortKey, this=exp.var(self._prev.text.upper()), compound=compound
    7286        )
    7287
    7288    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
    7289        index = self._index - 1
    7290
    7291        partition_exists = self._parse_exists()
    7292        if self._match(TokenType.PARTITION, advance=False):
    7293            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
    7294
    7295        self._retreat(index)
    7296        return self._parse_csv(self._parse_drop_column)
    7297
    7298    def _parse_alter_table_rename(self) -> t.Optional[exp.AlterRename | exp.RenameColumn]:
    7299        if self._match(TokenType.COLUMN):
    7300            exists = self._parse_exists()
    7301            old_column = self._parse_column()
    7302            to = self._match_text_seq("TO")
    7303            new_column = self._parse_column()
    7304
    7305            if old_column is None or to is None or new_column is None:
    7306                return None
    7307
    7308            return self.expression(exp.RenameColumn, this=old_column, to=new_column, exists=exists)
    7309
    7310        self._match_text_seq("TO")
    7311        return self.expression(exp.AlterRename, this=self._parse_table(schema=True))
    7312
    7313    def _parse_alter_table_set(self) -> exp.AlterSet:
    7314        alter_set = self.expression(exp.AlterSet)
    7315
    7316        if self._match(TokenType.L_PAREN, advance=False) or self._match_text_seq(
    7317            "TABLE", "PROPERTIES"
    7318        ):
    7319            alter_set.set("expressions", self._parse_wrapped_csv(self._parse_assignment))
    7320        elif self._match_text_seq("FILESTREAM_ON", advance=False):
    7321            alter_set.set("expressions", [self._parse_assignment()])
    7322        elif self._match_texts(("LOGGED", "UNLOGGED")):
    7323            alter_set.set("option", exp.var(self._prev.text.upper()))
    7324        elif self._match_text_seq("WITHOUT") and self._match_texts(("CLUSTER", "OIDS")):
    7325            alter_set.set("option", exp.var(f"WITHOUT {self._prev.text.upper()}"))
    7326        elif self._match_text_seq("LOCATION"):
    7327            alter_set.set("location", self._parse_field())
    7328        elif self._match_text_seq("ACCESS", "METHOD"):
    7329            alter_set.set("access_method", self._parse_field())
    7330        elif self._match_text_seq("TABLESPACE"):
    7331            alter_set.set("tablespace", self._parse_field())
    7332        elif self._match_text_seq("FILE", "FORMAT") or self._match_text_seq("FILEFORMAT"):
    7333            alter_set.set("file_format", [self._parse_field()])
    7334        elif self._match_text_seq("STAGE_FILE_FORMAT"):
    7335            alter_set.set("file_format", self._parse_wrapped_options())
    7336        elif self._match_text_seq("STAGE_COPY_OPTIONS"):
    7337            alter_set.set("copy_options", self._parse_wrapped_options())
    7338        elif self._match_text_seq("TAG") or self._match_text_seq("TAGS"):
    7339            alter_set.set("tag", self._parse_csv(self._parse_assignment))
    7340        else:
    7341            if self._match_text_seq("SERDE"):
    7342                alter_set.set("serde", self._parse_field())
    7343
    7344            alter_set.set("expressions", [self._parse_properties()])
    7345
    7346        return alter_set
    7347
    7348    def _parse_alter(self) -> exp.Alter | exp.Command:
    7349        start = self._prev
    7350
    7351        alter_token = self._match_set(self.ALTERABLES) and self._prev
    7352        if not alter_token:
    7353            return self._parse_as_command(start)
    7354
    7355        exists = self._parse_exists()
    7356        only = self._match_text_seq("ONLY")
    7357        this = self._parse_table(schema=True)
    7358        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
    7359
    7360        if self._next:
    7361            self._advance()
    7362
    7363        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
    7364        if parser:
    7365            actions = ensure_list(parser(self))
    7366            not_valid = self._match_text_seq("NOT", "VALID")
    7367            options = self._parse_csv(self._parse_property)
    7368
    7369            if not self._curr and actions:
    7370                return self.expression(
    7371                    exp.Alter,
    7372                    this=this,
    7373                    kind=alter_token.text.upper(),
    7374                    exists=exists,
    7375                    actions=actions,
    7376                    only=only,
    7377                    options=options,
    7378                    cluster=cluster,
    7379                    not_valid=not_valid,
    7380                )
    7381
    7382        return self._parse_as_command(start)
    7383
    7384    def _parse_analyze(self) -> exp.Analyze | exp.Command:
    7385        start = self._prev
    7386        # https://duckdb.org/docs/sql/statements/analyze
    7387        if not self._curr:
    7388            return self.expression(exp.Analyze)
    7389
    7390        options = []
    7391        while self._match_texts(self.ANALYZE_STYLES):
    7392            if self._prev.text.upper() == "BUFFER_USAGE_LIMIT":
    7393                options.append(f"BUFFER_USAGE_LIMIT {self._parse_number()}")
    7394            else:
    7395                options.append(self._prev.text.upper())
    7396
    7397        this: t.Optional[exp.Expression] = None
    7398        inner_expression: t.Optional[exp.Expression] = None
    7399
    7400        kind = self._curr and self._curr.text.upper()
    7401
    7402        if self._match(TokenType.TABLE) or self._match(TokenType.INDEX):
    7403            this = self._parse_table_parts()
    7404        elif self._match_text_seq("TABLES"):
    7405            if self._match_set((TokenType.FROM, TokenType.IN)):
    7406                kind = f"{kind} {self._prev.text.upper()}"
    7407                this = self._parse_table(schema=True, is_db_reference=True)
    7408        elif self._match_text_seq("DATABASE"):
    7409            this = self._parse_table(schema=True, is_db_reference=True)
    7410        elif self._match_text_seq("CLUSTER"):
    7411            this = self._parse_table()
    7412        # Try matching inner expr keywords before fallback to parse table.
    7413        elif self._match_texts(self.ANALYZE_EXPRESSION_PARSERS):
    7414            kind = None
    7415            inner_expression = self.ANALYZE_EXPRESSION_PARSERS[self._prev.text.upper()](self)
    7416        else:
    7417            # Empty kind  https://prestodb.io/docs/current/sql/analyze.html
    7418            kind = None
    7419            this = self._parse_table_parts()
    7420
    7421        partition = self._try_parse(self._parse_partition)
    7422        if not partition and self._match_texts(self.PARTITION_KEYWORDS):
    7423            return self._parse_as_command(start)
    7424
    7425        # https://docs.starrocks.io/docs/sql-reference/sql-statements/cbo_stats/ANALYZE_TABLE/
    7426        if self._match_text_seq("WITH", "SYNC", "MODE") or self._match_text_seq(
    7427            "WITH", "ASYNC", "MODE"
    7428        ):
    7429            mode = f"WITH {self._tokens[self._index - 2].text.upper()} MODE"
    7430        else:
    7431            mode = None
    7432
    7433        if self._match_texts(self.ANALYZE_EXPRESSION_PARSERS):
    7434            inner_expression = self.ANALYZE_EXPRESSION_PARSERS[self._prev.text.upper()](self)
    7435
    7436        properties = self._parse_properties()
    7437        return self.expression(
    7438            exp.Analyze,
    7439            kind=kind,
    7440            this=this,
    7441            mode=mode,
    7442            partition=partition,
    7443            properties=properties,
    7444            expression=inner_expression,
    7445            options=options,
    7446        )
    7447
    7448    # https://spark.apache.org/docs/3.5.1/sql-ref-syntax-aux-analyze-table.html
    7449    def _parse_analyze_statistics(self) -> exp.AnalyzeStatistics:
    7450        this = None
    7451        kind = self._prev.text.upper()
    7452        option = self._prev.text.upper() if self._match_text_seq("DELTA") else None
    7453        expressions = []
    7454
    7455        if not self._match_text_seq("STATISTICS"):
    7456            self.raise_error("Expecting token STATISTICS")
    7457
    7458        if self._match_text_seq("NOSCAN"):
    7459            this = "NOSCAN"
    7460        elif self._match(TokenType.FOR):
    7461            if self._match_text_seq("ALL", "COLUMNS"):
    7462                this = "FOR ALL COLUMNS"
    7463            if self._match_texts("COLUMNS"):
    7464                this = "FOR COLUMNS"
    7465                expressions = self._parse_csv(self._parse_column_reference)
    7466        elif self._match_text_seq("SAMPLE"):
    7467            sample = self._parse_number()
    7468            expressions = [
    7469                self.expression(
    7470                    exp.AnalyzeSample,
    7471                    sample=sample,
    7472                    kind=self._prev.text.upper() if self._match(TokenType.PERCENT) else None,
    7473                )
    7474            ]
    7475
    7476        return self.expression(
    7477            exp.AnalyzeStatistics, kind=kind, option=option, this=this, expressions=expressions
    7478        )
    7479
    7480    # https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/ANALYZE.html
    7481    def _parse_analyze_validate(self) -> exp.AnalyzeValidate:
    7482        kind = None
    7483        this = None
    7484        expression: t.Optional[exp.Expression] = None
    7485        if self._match_text_seq("REF", "UPDATE"):
    7486            kind = "REF"
    7487            this = "UPDATE"
    7488            if self._match_text_seq("SET", "DANGLING", "TO", "NULL"):
    7489                this = "UPDATE SET DANGLING TO NULL"
    7490        elif self._match_text_seq("STRUCTURE"):
    7491            kind = "STRUCTURE"
    7492            if self._match_text_seq("CASCADE", "FAST"):
    7493                this = "CASCADE FAST"
    7494            elif self._match_text_seq("CASCADE", "COMPLETE") and self._match_texts(
    7495                ("ONLINE", "OFFLINE")
    7496            ):
    7497                this = f"CASCADE COMPLETE {self._prev.text.upper()}"
    7498                expression = self._parse_into()
    7499
    7500        return self.expression(exp.AnalyzeValidate, kind=kind, this=this, expression=expression)
    7501
    7502    def _parse_analyze_columns(self) -> t.Optional[exp.AnalyzeColumns]:
    7503        this = self._prev.text.upper()
    7504        if self._match_text_seq("COLUMNS"):
    7505            return self.expression(exp.AnalyzeColumns, this=f"{this} {self._prev.text.upper()}")
    7506        return None
    7507
    7508    def _parse_analyze_delete(self) -> t.Optional[exp.AnalyzeDelete]:
    7509        kind = self._prev.text.upper() if self._match_text_seq("SYSTEM") else None
    7510        if self._match_text_seq("STATISTICS"):
    7511            return self.expression(exp.AnalyzeDelete, kind=kind)
    7512        return None
    7513
    7514    def _parse_analyze_list(self) -> t.Optional[exp.AnalyzeListChainedRows]:
    7515        if self._match_text_seq("CHAINED", "ROWS"):
    7516            return self.expression(exp.AnalyzeListChainedRows, expression=self._parse_into())
    7517        return None
    7518
    7519    # https://dev.mysql.com/doc/refman/8.4/en/analyze-table.html
    7520    def _parse_analyze_histogram(self) -> exp.AnalyzeHistogram:
    7521        this = self._prev.text.upper()
    7522        expression: t.Optional[exp.Expression] = None
    7523        expressions = []
    7524        update_options = None
    7525
    7526        if self._match_text_seq("HISTOGRAM", "ON"):
    7527            expressions = self._parse_csv(self._parse_column_reference)
    7528            with_expressions = []
    7529            while self._match(TokenType.WITH):
    7530                # https://docs.starrocks.io/docs/sql-reference/sql-statements/cbo_stats/ANALYZE_TABLE/
    7531                if self._match_texts(("SYNC", "ASYNC")):
    7532                    if self._match_text_seq("MODE", advance=False):
    7533                        with_expressions.append(f"{self._prev.text.upper()} MODE")
    7534                        self._advance()
    7535                else:
    7536                    buckets = self._parse_number()
    7537                    if self._match_text_seq("BUCKETS"):
    7538                        with_expressions.append(f"{buckets} BUCKETS")
    7539            if with_expressions:
    7540                expression = self.expression(exp.AnalyzeWith, expressions=with_expressions)
    7541
    7542            if self._match_texts(("MANUAL", "AUTO")) and self._match(
    7543                TokenType.UPDATE, advance=False
    7544            ):
    7545                update_options = self._prev.text.upper()
    7546                self._advance()
    7547            elif self._match_text_seq("USING", "DATA"):
    7548                expression = self.expression(exp.UsingData, this=self._parse_string())
    7549
    7550        return self.expression(
    7551            exp.AnalyzeHistogram,
    7552            this=this,
    7553            expressions=expressions,
    7554            expression=expression,
    7555            update_options=update_options,
    7556        )
    7557
    7558    def _parse_merge(self) -> exp.Merge:
    7559        self._match(TokenType.INTO)
    7560        target = self._parse_table()
    7561
    7562        if target and self._match(TokenType.ALIAS, advance=False):
    7563            target.set("alias", self._parse_table_alias())
    7564
    7565        self._match(TokenType.USING)
    7566        using = self._parse_table()
    7567
    7568        self._match(TokenType.ON)
    7569        on = self._parse_assignment()
    7570
    7571        return self.expression(
    7572            exp.Merge,
    7573            this=target,
    7574            using=using,
    7575            on=on,
    7576            whens=self._parse_when_matched(),
    7577            returning=self._parse_returning(),
    7578        )
    7579
    7580    def _parse_when_matched(self) -> exp.Whens:
    7581        whens = []
    7582
    7583        while self._match(TokenType.WHEN):
    7584            matched = not self._match(TokenType.NOT)
    7585            self._match_text_seq("MATCHED")
    7586            source = (
    7587                False
    7588                if self._match_text_seq("BY", "TARGET")
    7589                else self._match_text_seq("BY", "SOURCE")
    7590            )
    7591            condition = self._parse_assignment() if self._match(TokenType.AND) else None
    7592
    7593            self._match(TokenType.THEN)
    7594
    7595            if self._match(TokenType.INSERT):
    7596                this = self._parse_star()
    7597                if this:
    7598                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=this)
    7599                else:
    7600                    then = self.expression(
    7601                        exp.Insert,
    7602                        this=exp.var("ROW")
    7603                        if self._match_text_seq("ROW")
    7604                        else self._parse_value(values=False),
    7605                        expression=self._match_text_seq("VALUES") and self._parse_value(),
    7606                    )
    7607            elif self._match(TokenType.UPDATE):
    7608                expressions = self._parse_star()
    7609                if expressions:
    7610                    then = self.expression(exp.Update, expressions=expressions)
    7611                else:
    7612                    then = self.expression(
    7613                        exp.Update,
    7614                        expressions=self._match(TokenType.SET)
    7615                        and self._parse_csv(self._parse_equality),
    7616                    )
    7617            elif self._match(TokenType.DELETE):
    7618                then = self.expression(exp.Var, this=self._prev.text)
    7619            else:
    7620                then = self._parse_var_from_options(self.CONFLICT_ACTIONS)
    7621
    7622            whens.append(
    7623                self.expression(
    7624                    exp.When,
    7625                    matched=matched,
    7626                    source=source,
    7627                    condition=condition,
    7628                    then=then,
    7629                )
    7630            )
    7631        return self.expression(exp.Whens, expressions=whens)
    7632
    7633    def _parse_show(self) -> t.Optional[exp.Expression]:
    7634        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
    7635        if parser:
    7636            return parser(self)
    7637        return self._parse_as_command(self._prev)
    7638
    7639    def _parse_set_item_assignment(
    7640        self, kind: t.Optional[str] = None
    7641    ) -> t.Optional[exp.Expression]:
    7642        index = self._index
    7643
    7644        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
    7645            return self._parse_set_transaction(global_=kind == "GLOBAL")
    7646
    7647        left = self._parse_primary() or self._parse_column()
    7648        assignment_delimiter = self._match_texts(("=", "TO"))
    7649
    7650        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
    7651            self._retreat(index)
    7652            return None
    7653
    7654        right = self._parse_statement() or self._parse_id_var()
    7655        if isinstance(right, (exp.Column, exp.Identifier)):
    7656            right = exp.var(right.name)
    7657
    7658        this = self.expression(exp.EQ, this=left, expression=right)
    7659        return self.expression(exp.SetItem, this=this, kind=kind)
    7660
    7661    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
    7662        self._match_text_seq("TRANSACTION")
    7663        characteristics = self._parse_csv(
    7664            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
    7665        )
    7666        return self.expression(
    7667            exp.SetItem,
    7668            expressions=characteristics,
    7669            kind="TRANSACTION",
    7670            **{"global": global_},  # type: ignore
    7671        )
    7672
    7673    def _parse_set_item(self) -> t.Optional[exp.Expression]:
    7674        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
    7675        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
    7676
    7677    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
    7678        index = self._index
    7679        set_ = self.expression(
    7680            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
    7681        )
    7682
    7683        if self._curr:
    7684            self._retreat(index)
    7685            return self._parse_as_command(self._prev)
    7686
    7687        return set_
    7688
    7689    def _parse_var_from_options(
    7690        self, options: OPTIONS_TYPE, raise_unmatched: bool = True
    7691    ) -> t.Optional[exp.Var]:
    7692        start = self._curr
    7693        if not start:
    7694            return None
    7695
    7696        option = start.text.upper()
    7697        continuations = options.get(option)
    7698
    7699        index = self._index
    7700        self._advance()
    7701        for keywords in continuations or []:
    7702            if isinstance(keywords, str):
    7703                keywords = (keywords,)
    7704
    7705            if self._match_text_seq(*keywords):
    7706                option = f"{option} {' '.join(keywords)}"
    7707                break
    7708        else:
    7709            if continuations or continuations is None:
    7710                if raise_unmatched:
    7711                    self.raise_error(f"Unknown option {option}")
    7712
    7713                self._retreat(index)
    7714                return None
    7715
    7716        return exp.var(option)
    7717
    7718    def _parse_as_command(self, start: Token) -> exp.Command:
    7719        while self._curr:
    7720            self._advance()
    7721        text = self._find_sql(start, self._prev)
    7722        size = len(start.text)
    7723        self._warn_unsupported()
    7724        return exp.Command(this=text[:size], expression=text[size:])
    7725
    7726    def _parse_dict_property(self, this: str) -> exp.DictProperty:
    7727        settings = []
    7728
    7729        self._match_l_paren()
    7730        kind = self._parse_id_var()
    7731
    7732        if self._match(TokenType.L_PAREN):
    7733            while True:
    7734                key = self._parse_id_var()
    7735                value = self._parse_primary()
    7736                if not key and value is None:
    7737                    break
    7738                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
    7739            self._match(TokenType.R_PAREN)
    7740
    7741        self._match_r_paren()
    7742
    7743        return self.expression(
    7744            exp.DictProperty,
    7745            this=this,
    7746            kind=kind.this if kind else None,
    7747            settings=settings,
    7748        )
    7749
    7750    def _parse_dict_range(self, this: str) -> exp.DictRange:
    7751        self._match_l_paren()
    7752        has_min = self._match_text_seq("MIN")
    7753        if has_min:
    7754            min = self._parse_var() or self._parse_primary()
    7755            self._match_text_seq("MAX")
    7756            max = self._parse_var() or self._parse_primary()
    7757        else:
    7758            max = self._parse_var() or self._parse_primary()
    7759            min = exp.Literal.number(0)
    7760        self._match_r_paren()
    7761        return self.expression(exp.DictRange, this=this, min=min, max=max)
    7762
    7763    def _parse_comprehension(
    7764        self, this: t.Optional[exp.Expression]
    7765    ) -> t.Optional[exp.Comprehension]:
    7766        index = self._index
    7767        expression = self._parse_column()
    7768        if not self._match(TokenType.IN):
    7769            self._retreat(index - 1)
    7770            return None
    7771        iterator = self._parse_column()
    7772        condition = self._parse_assignment() if self._match_text_seq("IF") else None
    7773        return self.expression(
    7774            exp.Comprehension,
    7775            this=this,
    7776            expression=expression,
    7777            iterator=iterator,
    7778            condition=condition,
    7779        )
    7780
    7781    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
    7782        if self._match(TokenType.HEREDOC_STRING):
    7783            return self.expression(exp.Heredoc, this=self._prev.text)
    7784
    7785        if not self._match_text_seq("$"):
    7786            return None
    7787
    7788        tags = ["$"]
    7789        tag_text = None
    7790
    7791        if self._is_connected():
    7792            self._advance()
    7793            tags.append(self._prev.text.upper())
    7794        else:
    7795            self.raise_error("No closing $ found")
    7796
    7797        if tags[-1] != "$":
    7798            if self._is_connected() and self._match_text_seq("$"):
    7799                tag_text = tags[-1]
    7800                tags.append("$")
    7801            else:
    7802                self.raise_error("No closing $ found")
    7803
    7804        heredoc_start = self._curr
    7805
    7806        while self._curr:
    7807            if self._match_text_seq(*tags, advance=False):
    7808                this = self._find_sql(heredoc_start, self._prev)
    7809                self._advance(len(tags))
    7810                return self.expression(exp.Heredoc, this=this, tag=tag_text)
    7811
    7812            self._advance()
    7813
    7814        self.raise_error(f"No closing {''.join(tags)} found")
    7815        return None
    7816
    7817    def _find_parser(
    7818        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
    7819    ) -> t.Optional[t.Callable]:
    7820        if not self._curr:
    7821            return None
    7822
    7823        index = self._index
    7824        this = []
    7825        while True:
    7826            # The current token might be multiple words
    7827            curr = self._curr.text.upper()
    7828            key = curr.split(" ")
    7829            this.append(curr)
    7830
    7831            self._advance()
    7832            result, trie = in_trie(trie, key)
    7833            if result == TrieResult.FAILED:
    7834                break
    7835
    7836            if result == TrieResult.EXISTS:
    7837                subparser = parsers[" ".join(this)]
    7838                return subparser
    7839
    7840        self._retreat(index)
    7841        return None
    7842
    7843    def _match(self, token_type, advance=True, expression=None):
    7844        if not self._curr:
    7845            return None
    7846
    7847        if self._curr.token_type == token_type:
    7848            if advance:
    7849                self._advance()
    7850            self._add_comments(expression)
    7851            return True
    7852
    7853        return None
    7854
    7855    def _match_set(self, types, advance=True):
    7856        if not self._curr:
    7857            return None
    7858
    7859        if self._curr.token_type in types:
    7860            if advance:
    7861                self._advance()
    7862            return True
    7863
    7864        return None
    7865
    7866    def _match_pair(self, token_type_a, token_type_b, advance=True):
    7867        if not self._curr or not self._next:
    7868            return None
    7869
    7870        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
    7871            if advance:
    7872                self._advance(2)
    7873            return True
    7874
    7875        return None
    7876
    7877    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
    7878        if not self._match(TokenType.L_PAREN, expression=expression):
    7879            self.raise_error("Expecting (")
    7880
    7881    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
    7882        if not self._match(TokenType.R_PAREN, expression=expression):
    7883            self.raise_error("Expecting )")
    7884
    7885    def _match_texts(self, texts, advance=True):
    7886        if (
    7887            self._curr
    7888            and self._curr.token_type != TokenType.STRING
    7889            and self._curr.text.upper() in texts
    7890        ):
    7891            if advance:
    7892                self._advance()
    7893            return True
    7894        return None
    7895
    7896    def _match_text_seq(self, *texts, advance=True):
    7897        index = self._index
    7898        for text in texts:
    7899            if (
    7900                self._curr
    7901                and self._curr.token_type != TokenType.STRING
    7902                and self._curr.text.upper() == text
    7903            ):
    7904                self._advance()
    7905            else:
    7906                self._retreat(index)
    7907                return None
    7908
    7909        if not advance:
    7910            self._retreat(index)
    7911
    7912        return True
    7913
    7914    def _replace_lambda(
    7915        self, node: t.Optional[exp.Expression], expressions: t.List[exp.Expression]
    7916    ) -> t.Optional[exp.Expression]:
    7917        if not node:
    7918            return node
    7919
    7920        lambda_types = {e.name: e.args.get("to") or False for e in expressions}
    7921
    7922        for column in node.find_all(exp.Column):
    7923            typ = lambda_types.get(column.parts[0].name)
    7924            if typ is not None:
    7925                dot_or_id = column.to_dot() if column.table else column.this
    7926
    7927                if typ:
    7928                    dot_or_id = self.expression(
    7929                        exp.Cast,
    7930                        this=dot_or_id,
    7931                        to=typ,
    7932                    )
    7933
    7934                parent = column.parent
    7935
    7936                while isinstance(parent, exp.Dot):
    7937                    if not isinstance(parent.parent, exp.Dot):
    7938                        parent.replace(dot_or_id)
    7939                        break
    7940                    parent = parent.parent
    7941                else:
    7942                    if column is node:
    7943                        node = dot_or_id
    7944                    else:
    7945                        column.replace(dot_or_id)
    7946        return node
    7947
    7948    def _parse_truncate_table(self) -> t.Optional[exp.TruncateTable] | exp.Expression:
    7949        start = self._prev
    7950
    7951        # Not to be confused with TRUNCATE(number, decimals) function call
    7952        if self._match(TokenType.L_PAREN):
    7953            self._retreat(self._index - 2)
    7954            return self._parse_function()
    7955
    7956        # Clickhouse supports TRUNCATE DATABASE as well
    7957        is_database = self._match(TokenType.DATABASE)
    7958
    7959        self._match(TokenType.TABLE)
    7960
    7961        exists = self._parse_exists(not_=False)
    7962
    7963        expressions = self._parse_csv(
    7964            lambda: self._parse_table(schema=True, is_db_reference=is_database)
    7965        )
    7966
    7967        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
    7968
    7969        if self._match_text_seq("RESTART", "IDENTITY"):
    7970            identity = "RESTART"
    7971        elif self._match_text_seq("CONTINUE", "IDENTITY"):
    7972            identity = "CONTINUE"
    7973        else:
    7974            identity = None
    7975
    7976        if self._match_text_seq("CASCADE") or self._match_text_seq("RESTRICT"):
    7977            option = self._prev.text
    7978        else:
    7979            option = None
    7980
    7981        partition = self._parse_partition()
    7982
    7983        # Fallback case
    7984        if self._curr:
    7985            return self._parse_as_command(start)
    7986
    7987        return self.expression(
    7988            exp.TruncateTable,
    7989            expressions=expressions,
    7990            is_database=is_database,
    7991            exists=exists,
    7992            cluster=cluster,
    7993            identity=identity,
    7994            option=option,
    7995            partition=partition,
    7996        )
    7997
    7998    def _parse_with_operator(self) -> t.Optional[exp.Expression]:
    7999        this = self._parse_ordered(self._parse_opclass)
    8000
    8001        if not self._match(TokenType.WITH):
    8002            return this
    8003
    8004        op = self._parse_var(any_token=True)
    8005
    8006        return self.expression(exp.WithOperator, this=this, op=op)
    8007
    8008    def _parse_wrapped_options(self) -> t.List[t.Optional[exp.Expression]]:
    8009        self._match(TokenType.EQ)
    8010        self._match(TokenType.L_PAREN)
    8011
    8012        opts: t.List[t.Optional[exp.Expression]] = []
    8013        option: exp.Expression | None
    8014        while self._curr and not self._match(TokenType.R_PAREN):
    8015            if self._match_text_seq("FORMAT_NAME", "="):
    8016                # The FORMAT_NAME can be set to an identifier for Snowflake and T-SQL
    8017                option = self._parse_format_name()
    8018            else:
    8019                option = self._parse_property()
    8020
    8021            if option is None:
    8022                self.raise_error("Unable to parse option")
    8023                break
    8024
    8025            opts.append(option)
    8026
    8027        return opts
    8028
    8029    def _parse_copy_parameters(self) -> t.List[exp.CopyParameter]:
    8030        sep = TokenType.COMMA if self.dialect.COPY_PARAMS_ARE_CSV else None
    8031
    8032        options = []
    8033        while self._curr and not self._match(TokenType.R_PAREN, advance=False):
    8034            option = self._parse_var(any_token=True)
    8035            prev = self._prev.text.upper()
    8036
    8037            # Different dialects might separate options and values by white space, "=" and "AS"
    8038            self._match(TokenType.EQ)
    8039            self._match(TokenType.ALIAS)
    8040
    8041            param = self.expression(exp.CopyParameter, this=option)
    8042
    8043            if prev in self.COPY_INTO_VARLEN_OPTIONS and self._match(
    8044                TokenType.L_PAREN, advance=False
    8045            ):
    8046                # Snowflake FILE_FORMAT case, Databricks COPY & FORMAT options
    8047                param.set("expressions", self._parse_wrapped_options())
    8048            elif prev == "FILE_FORMAT":
    8049                # T-SQL's external file format case
    8050                param.set("expression", self._parse_field())
    8051            else:
    8052                param.set("expression", self._parse_unquoted_field())
    8053
    8054            options.append(param)
    8055            self._match(sep)
    8056
    8057        return options
    8058
    8059    def _parse_credentials(self) -> t.Optional[exp.Credentials]:
    8060        expr = self.expression(exp.Credentials)
    8061
    8062        if self._match_text_seq("STORAGE_INTEGRATION", "="):
    8063            expr.set("storage", self._parse_field())
    8064        if self._match_text_seq("CREDENTIALS"):
    8065            # Snowflake case: CREDENTIALS = (...), Redshift case: CREDENTIALS <string>
    8066            creds = (
    8067                self._parse_wrapped_options() if self._match(TokenType.EQ) else self._parse_field()
    8068            )
    8069            expr.set("credentials", creds)
    8070        if self._match_text_seq("ENCRYPTION"):
    8071            expr.set("encryption", self._parse_wrapped_options())
    8072        if self._match_text_seq("IAM_ROLE"):
    8073            expr.set("iam_role", self._parse_field())
    8074        if self._match_text_seq("REGION"):
    8075            expr.set("region", self._parse_field())
    8076
    8077        return expr
    8078
    8079    def _parse_file_location(self) -> t.Optional[exp.Expression]:
    8080        return self._parse_field()
    8081
    8082    def _parse_copy(self) -> exp.Copy | exp.Command:
    8083        start = self._prev
    8084
    8085        self._match(TokenType.INTO)
    8086
    8087        this = (
    8088            self._parse_select(nested=True, parse_subquery_alias=False)
    8089            if self._match(TokenType.L_PAREN, advance=False)
    8090            else self._parse_table(schema=True)
    8091        )
    8092
    8093        kind = self._match(TokenType.FROM) or not self._match_text_seq("TO")
    8094
    8095        files = self._parse_csv(self._parse_file_location)
    8096        credentials = self._parse_credentials()
    8097
    8098        self._match_text_seq("WITH")
    8099
    8100        params = self._parse_wrapped(self._parse_copy_parameters, optional=True)
    8101
    8102        # Fallback case
    8103        if self._curr:
    8104            return self._parse_as_command(start)
    8105
    8106        return self.expression(
    8107            exp.Copy,
    8108            this=this,
    8109            kind=kind,
    8110            credentials=credentials,
    8111            files=files,
    8112            params=params,
    8113        )
    8114
    8115    def _parse_normalize(self) -> exp.Normalize:
    8116        return self.expression(
    8117            exp.Normalize,
    8118            this=self._parse_bitwise(),
    8119            form=self._match(TokenType.COMMA) and self._parse_var(),
    8120        )
    8121
    8122    def _parse_ceil_floor(self, expr_type: t.Type[TCeilFloor]) -> TCeilFloor:
    8123        args = self._parse_csv(lambda: self._parse_lambda())
    8124
    8125        this = seq_get(args, 0)
    8126        decimals = seq_get(args, 1)
    8127
    8128        return expr_type(
    8129            this=this, decimals=decimals, to=self._match_text_seq("TO") and self._parse_var()
    8130        )
    8131
    8132    def _parse_star_ops(self) -> t.Optional[exp.Expression]:
    8133        if self._match_text_seq("COLUMNS", "(", advance=False):
    8134            this = self._parse_function()
    8135            if isinstance(this, exp.Columns):
    8136                this.set("unpack", True)
    8137            return this
    8138
    8139        return self.expression(
    8140            exp.Star,
    8141            **{  # type: ignore
    8142                "except": self._parse_star_op("EXCEPT", "EXCLUDE"),
    8143                "replace": self._parse_star_op("REPLACE"),
    8144                "rename": self._parse_star_op("RENAME"),
    8145            },
    8146        )
    8147
    8148    def _parse_grant_privilege(self) -> t.Optional[exp.GrantPrivilege]:
    8149        privilege_parts = []
    8150
    8151        # Keep consuming consecutive keywords until comma (end of this privilege) or ON
    8152        # (end of privilege list) or L_PAREN (start of column list) are met
    8153        while self._curr and not self._match_set(self.PRIVILEGE_FOLLOW_TOKENS, advance=False):
    8154            privilege_parts.append(self._curr.text.upper())
    8155            self._advance()
    8156
    8157        this = exp.var(" ".join(privilege_parts))
    8158        expressions = (
    8159            self._parse_wrapped_csv(self._parse_column)
    8160            if self._match(TokenType.L_PAREN, advance=False)
    8161            else None
    8162        )
    8163
    8164        return self.expression(exp.GrantPrivilege, this=this, expressions=expressions)
    8165
    8166    def _parse_grant_principal(self) -> t.Optional[exp.GrantPrincipal]:
    8167        kind = self._match_texts(("ROLE", "GROUP")) and self._prev.text.upper()
    8168        principal = self._parse_id_var()
    8169
    8170        if not principal:
    8171            return None
    8172
    8173        return self.expression(exp.GrantPrincipal, this=principal, kind=kind)
    8174
    8175    def _parse_grant(self) -> exp.Grant | exp.Command:
    8176        start = self._prev
    8177
    8178        privileges = self._parse_csv(self._parse_grant_privilege)
    8179
    8180        self._match(TokenType.ON)
    8181        kind = self._match_set(self.CREATABLES) and self._prev.text.upper()
    8182
    8183        # Attempt to parse the securable e.g. MySQL allows names
    8184        # such as "foo.*", "*.*" which are not easily parseable yet
    8185        securable = self._try_parse(self._parse_table_parts)
    8186
    8187        if not securable or not self._match_text_seq("TO"):
    8188            return self._parse_as_command(start)
    8189
    8190        principals = self._parse_csv(self._parse_grant_principal)
    8191
    8192        grant_option = self._match_text_seq("WITH", "GRANT", "OPTION")
    8193
    8194        if self._curr:
    8195            return self._parse_as_command(start)
    8196
    8197        return self.expression(
    8198            exp.Grant,
    8199            privileges=privileges,
    8200            kind=kind,
    8201            securable=securable,
    8202            principals=principals,
    8203            grant_option=grant_option,
    8204        )
    8205
    8206    def _parse_overlay(self) -> exp.Overlay:
    8207        return self.expression(
    8208            exp.Overlay,
    8209            **{  # type: ignore
    8210                "this": self._parse_bitwise(),
    8211                "expression": self._match_text_seq("PLACING") and self._parse_bitwise(),
    8212                "from": self._match_text_seq("FROM") and self._parse_bitwise(),
    8213                "for": self._match_text_seq("FOR") and self._parse_bitwise(),
    8214            },
    8215        )
    8216
    8217    def _parse_format_name(self) -> exp.Property:
    8218        # Note: Although not specified in the docs, Snowflake does accept a string/identifier
    8219        # for FILE_FORMAT = <format_name>
    8220        return self.expression(
    8221            exp.Property,
    8222            this=exp.var("FORMAT_NAME"),
    8223            value=self._parse_string() or self._parse_table_parts(),
    8224        )

Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.

###### Arguments:

- error_level: The desired error level. Default: ErrorLevel.IMMEDIATE
- error_message_context: The amount of context to capture from a query string when displaying the error message (in number of characters). Default: 100
- max_errors: Maximum number of error messages to include in a raised ParseError. This is only relevant if error_level is ErrorLevel.RAISE. Default: 3

Parser( error_level: Optional[sqlglot.errors.ErrorLevel] = None, error_message_context: int = 100, max_errors: int = 3, dialect: Union[str, sqlglot.dialects.Dialect, Type[sqlglot.dialects.Dialect], NoneType] = None) View Source

    1502    def __init__(
    1503        self,
    1504        error_level: t.Optional[ErrorLevel] = None,
    1505        error_message_context: int = 100,
    1506        max_errors: int = 3,
    1507        dialect: DialectType = None,
    1508    ):
    1509        from sqlglot.dialects import Dialect
    1510
    1511        self.error_level = error_level or ErrorLevel.IMMEDIATE
    1512        self.error_message_context = error_message_context
    1513        self.max_errors = max_errors
    1514        self.dialect = Dialect.get_or_raise(dialect)
    1515        self.reset()

FUNCTIONS: Dict[str, Callable] = {'ABS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Abs'>>, 'ADD_MONTHS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AddMonths'>>, 'AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.And'>>, 'ANONYMOUS_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AnonymousAggFunc'>>, 'ANY_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AnyValue'>>, 'APPLY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Apply'>>, 'APPROX_DISTINCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxDistinct'>>, 'APPROX_COUNT_DISTINCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxDistinct'>>, 'APPROX_QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxQuantile'>>, 'APPROX_TOP_K': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxTopK'>>, 'ARG_MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'ARGMAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'MAX_BY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'ARG_MIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'ARGMIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'MIN_BY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'ARRAY': <function Parser.<lambda>>, 'ARRAY_AGG': <function Parser.<lambda>>, 'ARRAY_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAll'>>, 'ARRAY_ANY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAny'>>, 'ARRAY_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConcat'>>, 'ARRAY_CAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConcat'>>, 'ARRAY_CONSTRUCT_COMPACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConstructCompact'>>, 'ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContains'>>, 'ARRAY_HAS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContains'>>, 'ARRAY_CONTAINS_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContainsAll'>>, 'ARRAY_HAS_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContainsAll'>>, 'FILTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayFilter'>>, 'ARRAY_FILTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayFilter'>>, 'ARRAY_OVERLAPS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayOverlaps'>>, 'ARRAY_SIZE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySize'>>, 'ARRAY_LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySize'>>, 'ARRAY_SORT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySort'>>, 'ARRAY_SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySum'>>, 'ARRAY_TO_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayToString'>>, 'ARRAY_JOIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayToString'>>, 'ARRAY_UNION_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUnionAgg'>>, 'ARRAY_UNIQUE_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUniqueAgg'>>, 'AVG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Avg'>>, 'CASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Case'>>, 'CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Cast'>>, 'CAST_TO_STR_TYPE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CastToStrType'>>, 'CBRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Cbrt'>>, 'CEIL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CEILING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CHR': <function Parser.<lambda>>, 'CHAR': <function Parser.<lambda>>, 'COALESCE': <function build_coalesce>, 'IFNULL': <function build_coalesce>, 'NVL': <function build_coalesce>, 'COLLATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Collate'>>, 'COLUMNS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Columns'>>, 'COMBINED_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedAggFunc'>>, 'COMBINED_PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedParameterizedAgg'>>, 'CONCAT': <function Parser.<lambda>>, 'CONCAT_WS': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ConnectByRoot'>>, 'CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Contains'>>, 'CONVERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Convert'>>, 'CONVERT_TIMEZONE': <function build_convert_timezone>, 'CORR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Corr'>>, 'COUNT': <function Parser.<lambda>>, 'COUNT_IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, 'COUNTIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, 'COVAR_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CovarPop'>>, 'COVAR_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CovarSamp'>>, 'CURRENT_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDate'>>, 'CURRENT_DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDatetime'>>, 'CURRENT_SCHEMA': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentSchema'>>, 'CURRENT_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTime'>>, 'CURRENT_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTimestamp'>>, 'CURRENT_USER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentUser'>>, 'DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Date'>>, 'DATE_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateAdd'>>, 'DATE_BIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateBin'>>, 'DATEDIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateDiff'>>, 'DATE_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateDiff'>>, 'DATE_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromParts'>>, 'DATEFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromParts'>>, 'DATE_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateStrToDate'>>, 'DATE_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateSub'>>, 'DATE_TO_DATE_STR': <function Parser.<lambda>>, 'DATE_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateToDi'>>, 'DATE_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateTrunc'>>, 'DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Datetime'>>, 'DATETIME_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeAdd'>>, 'DATETIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeDiff'>>, 'DATETIME_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeSub'>>, 'DATETIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeTrunc'>>, 'DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Day'>>, 'DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfMonth'>>, 'DAYOFMONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfMonth'>>, 'DAY_OF_WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeek'>>, 'DAYOFWEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeek'>>, 'DAYOFWEEK_ISO': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeekIso'>>, 'ISODOW': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeekIso'>>, 'DAY_OF_YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfYear'>>, 'DAYOFYEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfYear'>>, 'DECODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Decode'>>, 'DI_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DiToDate'>>, 'ENCODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Encode'>>, 'EXISTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Exists'>>, 'EXP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Exp'>>, 'EXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Explode'>>, 'EXPLODE_OUTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ExplodeOuter'>>, 'EXPLODING_GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ExplodingGenerateSeries'>>, 'EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Extract'>>, 'FEATURES_AT_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FeaturesAtTime'>>, 'FIRST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.First'>>, 'FIRST_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FirstValue'>>, 'FLATTEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Flatten'>>, 'FLOOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Floor'>>, 'FROM_BASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase'>>, 'FROM_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase64'>>, 'FROM_ISO8601_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromISO8601Timestamp'>>, 'GAP_FILL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GapFill'>>, 'GENERATE_DATE_ARRAY': <function Parser.<lambda>>, 'GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateSeries'>>, 'GENERATE_TIMESTAMP_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateTimestampArray'>>, 'GREATEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Greatest'>>, 'GROUP_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GroupConcat'>>, 'HEX': <function build_hex>, 'HLL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Hll'>>, 'IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.If'>>, 'IIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.If'>>, 'INITCAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Initcap'>>, 'INLINE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Inline'>>, 'INT64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Int64'>>, 'IS_ASCII': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsAscii'>>, 'IS_INF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsInf'>>, 'ISINF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsInf'>>, 'IS_NAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsNan'>>, 'ISNAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsNan'>>, 'J_S_O_N_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArray'>>, 'J_S_O_N_ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayAgg'>>, 'JSON_ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayContains'>>, 'JSONB_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBContains'>>, 'JSONB_EXISTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExists'>>, 'JSONB_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtract'>>, 'JSONB_EXTRACT_SCALAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtractScalar'>>, 'J_S_O_N_B_OBJECT_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBObjectAgg'>>, 'J_S_O_N_CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONCast'>>, 'J_S_O_N_EXISTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExists'>>, 'JSON_EXTRACT': <function build_extract_json_with_path.<locals>._builder>, 'JSON_EXTRACT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExtractArray'>>, 'JSON_EXTRACT_SCALAR': <function build_extract_json_with_path.<locals>._builder>, 'JSON_FORMAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONFormat'>>, 'J_S_O_N_OBJECT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObject'>>, 'J_S_O_N_OBJECT_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObjectAgg'>>, 'J_S_O_N_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONTable'>>, 'J_S_O_N_VALUE_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONValueArray'>>, 'LAG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lag'>>, 'LAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Last'>>, 'LAST_DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastValue'>>, 'LEAD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lead'>>, 'LEAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Least'>>, 'LEFT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Left'>>, 'LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'CHAR_LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'CHARACTER_LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEVENSHTEIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Levenshtein'>>, 'LIST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.List'>>, 'LN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ln'>>, 'LOG': <function build_logarithm>, 'LOGICAL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOLAND_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'LOGICAL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOLOR_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'LOWER': <function build_lower>, 'LCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'LOWER_HEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LowerHex'>>, 'MD5': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5'>>, 'MD5_DIGEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5Digest'>>, 'MAKE_INTERVAL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MakeInterval'>>, 'MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Map'>>, 'MAP_FROM_ENTRIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MapFromEntries'>>, 'MATCH_AGAINST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MatchAgainst'>>, 'MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Max'>>, 'MEDIAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Median'>>, 'MIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Min'>>, 'MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Month'>>, 'MONTHS_BETWEEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MonthsBetween'>>, 'NEXT_VALUE_FOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NextValueFor'>>, 'NORMALIZE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Normalize'>>, 'NTH_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NthValue'>>, 'NULLIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nullif'>>, 'NUMBER_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NumberToStr'>>, 'NVL2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nvl2'>>, 'OBJECT_INSERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ObjectInsert'>>, 'OPEN_J_S_O_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.OpenJSON'>>, 'OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Or'>>, 'OVERLAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Overlay'>>, 'PAD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pad'>>, 'PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParameterizedAgg'>>, 'PARSE_JSON': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'JSON_PARSE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'PERCENTILE_CONT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileCont'>>, 'PERCENTILE_DISC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileDisc'>>, 'POSEXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Posexplode'>>, 'POSEXPLODE_OUTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PosexplodeOuter'>>, 'POWER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'POW': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'PREDICT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Predict'>>, 'QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quantile'>>, 'QUARTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quarter'>>, 'RAND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rand'>>, 'RANDOM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rand'>>, 'RANDN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Randn'>>, 'RANGE_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RangeN'>>, 'READ_CSV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ReadCSV'>>, 'REDUCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Reduce'>>, 'REGEXP_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpExtract'>>, 'REGEXP_EXTRACT_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpExtractAll'>>, 'REGEXP_I_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpILike'>>, 'REGEXP_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpLike'>>, 'REGEXP_REPLACE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpReplace'>>, 'REGEXP_SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpSplit'>>, 'REPEAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Repeat'>>, 'RIGHT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Right'>>, 'ROUND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Round'>>, 'ROW_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RowNumber'>>, 'SHA': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA1': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA2'>>, 'SAFE_DIVIDE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeDivide'>>, 'SIGN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SIGNUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SORT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SortArray'>>, 'SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Split'>>, 'SPLIT_PART': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SplitPart'>>, 'SQRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sqrt'>>, 'STANDARD_HASH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StandardHash'>>, 'STAR_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StarMap'>>, 'STARTS_WITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STARTSWITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STDDEV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stddev'>>, 'STDEV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stddev'>>, 'STDDEV_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevPop'>>, 'STDDEV_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevSamp'>>, 'STR_POSITION': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToDate'>>, 'STR_TO_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToMap'>>, 'STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToTime'>>, 'STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToUnix'>>, 'STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.String'>>, 'STRING_TO_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StringToArray'>>, 'SPLIT_BY_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StringToArray'>>, 'STRUCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Struct'>>, 'STRUCT_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StructExtract'>>, 'STUFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'INSERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'SUBSTRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Substring'>>, 'SUBSTR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Substring'>>, 'SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sum'>>, 'TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Time'>>, 'TIME_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeAdd'>>, 'TIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeDiff'>>, 'TIME_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeFromParts'>>, 'TIMEFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeFromParts'>>, 'TIME_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToDate'>>, 'TIME_STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToTime'>>, 'TIME_STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToUnix'>>, 'TIME_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeSub'>>, 'TIME_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToStr'>>, 'TIME_TO_TIME_STR': <function Parser.<lambda>>, 'TIME_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToUnix'>>, 'TIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeTrunc'>>, 'TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Timestamp'>>, 'TIMESTAMP_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampAdd'>>, 'TIMESTAMPDIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, 'TIMESTAMPFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, 'TIMESTAMP_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampSub'>>, 'TIMESTAMP_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampTrunc'>>, 'TO_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToArray'>>, 'TO_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToBase64'>>, 'TO_CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToChar'>>, 'TO_DAYS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToDays'>>, 'TO_DOUBLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToDouble'>>, 'TO_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToMap'>>, 'TO_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToNumber'>>, 'TRANSFORM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Transform'>>, 'TRIM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Trim'>>, 'TRY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Try'>>, 'TRY_CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TryCast'>>, 'TS_OR_DI_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDiToDi'>>, 'TS_OR_DS_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsAdd'>>, 'TS_OR_DS_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsDiff'>>, 'TS_OR_DS_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToDate'>>, 'TS_OR_DS_TO_DATE_STR': <function Parser.<lambda>>, 'TS_OR_DS_TO_DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToDatetime'>>, 'TS_OR_DS_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTime'>>, 'TS_OR_DS_TO_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTimestamp'>>, 'UNHEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unhex'>>, 'UNICODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unicode'>>, 'UNIX_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixDate'>>, 'UNIX_SECONDS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixSeconds'>>, 'UNIX_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToStr'>>, 'UNIX_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTime'>>, 'UNIX_TO_TIME_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTimeStr'>>, 'UNNEST': <function Parser.<lambda>>, 'UPPER': <function build_upper>, 'UCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Upper'>>, 'UUID': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Uuid'>>, 'GEN_RANDOM_UUID': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Uuid'>>, 'GENERATE_UUID': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Uuid'>>, 'UUID_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Uuid'>>, 'VAR_MAP': <function build_var_map>, 'VARIANCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VAR_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'VAR_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Week'>>, 'WEEK_OF_YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'WEEKOFYEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'XMLELEMENT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.XMLElement'>>, 'X_M_L_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.XMLTable'>>, 'XOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Xor'>>, 'YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Year'>>, 'ARRAYAGG': <function Parser.<lambda>>, 'GLOB': <function Parser.<lambda>>, 'JSON_EXTRACT_PATH_TEXT': <function build_extract_json_with_path.<locals>._builder>, 'LIKE': <function build_like>, 'LOG2': <function Parser.<lambda>>, 'LOG10': <function Parser.<lambda>>, 'LPAD': <function Parser.<lambda>>, 'LEFTPAD': <function Parser.<lambda>>, 'LTRIM': <function Parser.<lambda>>, 'MOD': <function build_mod>, 'RIGHTPAD': <function Parser.<lambda>>, 'RPAD': <function Parser.<lambda>>, 'RTRIM': <function Parser.<lambda>>, 'SCOPE_RESOLUTION': <function Parser.<lambda>>, 'STRPOS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'CHARINDEX': <function Parser.<lambda>>, 'INSTR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'LOCATE': <function Parser.<lambda>>, 'TO_HEX': <function build_hex>}
NO_PAREN_FUNCTIONS = {<TokenType.CURRENT_DATE: 'CURRENT_DATE'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>: <class 'sqlglot.expressions.CurrentTime'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>: <class 'sqlglot.expressions.CurrentTimestamp'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>: <class 'sqlglot.expressions.CurrentUser'>}
STRUCT_TYPE_TOKENS = {<TokenType.OBJECT: 'OBJECT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.UNION: 'UNION'>, <TokenType.STRUCT: 'STRUCT'>}
NESTED_TYPE_TOKENS = {<TokenType.ARRAY: 'ARRAY'>, <TokenType.MAP: 'MAP'>, <TokenType.UNION: 'UNION'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.LIST: 'LIST'>, <TokenType.RANGE: 'RANGE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.NESTED: 'NESTED'>}
ENUM_TYPE_TOKENS = {<TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM: 'ENUM'>}
AGGREGATE_TYPE_TOKENS = {<TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>}
TYPE_TOKENS = {<TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.MONEY: 'MONEY'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.JSON: 'JSON'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.RING: 'RING'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.INT256: 'INT256'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INET: 'INET'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.BLOB: 'BLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LIST: 'LIST'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.UINT: 'UINT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NULL: 'NULL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.POINT: 'POINT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIME: 'TIME'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.INT: 'INT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM: 'ENUM'>, <TokenType.XML: 'XML'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UNION: 'UNION'>, <TokenType.DATE: 'DATE'>, <TokenType.INT128: 'INT128'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NAME: 'NAME'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.MAP: 'MAP'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>}
SIGNED_TO_UNSIGNED_TYPE_TOKEN = {<TokenType.BIGINT: 'BIGINT'>: <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INT: 'INT'>: <TokenType.UINT: 'UINT'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>: <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SMALLINT: 'SMALLINT'>: <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TINYINT: 'TINYINT'>: <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.DECIMAL: 'DECIMAL'>: <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.DOUBLE: 'DOUBLE'>: <TokenType.UDOUBLE: 'UDOUBLE'>}
SUBQUERY_PREDICATES = {<TokenType.ANY: 'ANY'>: <class 'sqlglot.expressions.Any'>, <TokenType.ALL: 'ALL'>: <class 'sqlglot.expressions.All'>, <TokenType.EXISTS: 'EXISTS'>: <class 'sqlglot.expressions.Exists'>, <TokenType.SOME: 'SOME'>: <class 'sqlglot.expressions.Any'>}
RESERVED_TOKENS = {<TokenType.CARET: 'CARET'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.TILDA: 'TILDA'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.COMMA: 'COMMA'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.EQ: 'EQ'>, <TokenType.LT: 'LT'>, <TokenType.PLUS: 'PLUS'>, <TokenType.DOT: 'DOT'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.HASH: 'HASH'>, <TokenType.MOD: 'MOD'>, <TokenType.SLASH: 'SLASH'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.PIPE: 'PIPE'>, <TokenType.GT: 'GT'>, <TokenType.SELECT: 'SELECT'>, <TokenType.STAR: 'STAR'>, <TokenType.NOT: 'NOT'>, <TokenType.DASH: 'DASH'>, <TokenType.COLON: 'COLON'>, <TokenType.AMP: 'AMP'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.L_BRACE: 'L_BRACE'>}
DB_CREATABLES = {<TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.STAGE: 'STAGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SINK: 'SINK'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TAG: 'TAG'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.SOURCE: 'SOURCE'>}
CREATABLES = {<TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.MODEL: 'MODEL'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SINK: 'SINK'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TAG: 'TAG'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.TABLE: 'TABLE'>, <TokenType.STAGE: 'STAGE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>}
ALTERABLES = {<TokenType.VIEW: 'VIEW'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TABLE: 'TABLE'>}
ID_VAR_TOKENS = {<TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TOP: 'TOP'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SET: 'SET'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.JSON: 'JSON'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COPY: 'COPY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.RING: 'RING'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USE: 'USE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DESC: 'DESC'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.ASC: 'ASC'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT256: 'INT256'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INET: 'INET'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TAG: 'TAG'>, <TokenType.YEAR: 'YEAR'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.FILTER: 'FILTER'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DETACH: 'DETACH'>, <TokenType.BLOB: 'BLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LIST: 'LIST'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UINT: 'UINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IS: 'IS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NULL: 'NULL'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.ROW: 'ROW'>, <TokenType.ASOF: 'ASOF'>, <TokenType.CASE: 'CASE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.POINT: 'POINT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIME: 'TIME'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.INT: 'INT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TRUE: 'TRUE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.DIV: 'DIV'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FULL: 'FULL'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.ANY: 'ANY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.END: 'END'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.CUBE: 'CUBE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM: 'ENUM'>, <TokenType.XML: 'XML'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.VAR: 'VAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.APPLY: 'APPLY'>, <TokenType.SOME: 'SOME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DATE: 'DATE'>, <TokenType.INT128: 'INT128'>, <TokenType.SINK: 'SINK'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ROWS: 'ROWS'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.DELETE: 'DELETE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NAME: 'NAME'>, <TokenType.PUT: 'PUT'>, <TokenType.RENAME: 'RENAME'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.KEEP: 'KEEP'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.STAGE: 'STAGE'>, <TokenType.MAP: 'MAP'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.KILL: 'KILL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.REPLACE: 'REPLACE'>}
TABLE_ALIAS_TOKENS = {<TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TOP: 'TOP'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SET: 'SET'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.JSON: 'JSON'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COPY: 'COPY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.RING: 'RING'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USE: 'USE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DESC: 'DESC'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.ASC: 'ASC'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT256: 'INT256'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INET: 'INET'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TAG: 'TAG'>, <TokenType.YEAR: 'YEAR'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.FILTER: 'FILTER'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DETACH: 'DETACH'>, <TokenType.BLOB: 'BLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LIST: 'LIST'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UINT: 'UINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.IS: 'IS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NULL: 'NULL'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.ROW: 'ROW'>, <TokenType.CASE: 'CASE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.POINT: 'POINT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIME: 'TIME'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.INT: 'INT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TRUE: 'TRUE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.DIV: 'DIV'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.FIRST: 'FIRST'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.ANY: 'ANY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.END: 'END'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.CUBE: 'CUBE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM: 'ENUM'>, <TokenType.XML: 'XML'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.VAR: 'VAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SOME: 'SOME'>, <TokenType.DATE: 'DATE'>, <TokenType.INT128: 'INT128'>, <TokenType.SINK: 'SINK'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ROWS: 'ROWS'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.DELETE: 'DELETE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NAME: 'NAME'>, <TokenType.PUT: 'PUT'>, <TokenType.RENAME: 'RENAME'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.KEEP: 'KEEP'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.STAGE: 'STAGE'>, <TokenType.MAP: 'MAP'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.KILL: 'KILL'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.REPLACE: 'REPLACE'>}
ALIAS_TOKENS = {<TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TOP: 'TOP'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SET: 'SET'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.JSON: 'JSON'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COPY: 'COPY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.RING: 'RING'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USE: 'USE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DESC: 'DESC'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.ASC: 'ASC'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT256: 'INT256'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INET: 'INET'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TAG: 'TAG'>, <TokenType.YEAR: 'YEAR'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.FILTER: 'FILTER'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DETACH: 'DETACH'>, <TokenType.BLOB: 'BLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LIST: 'LIST'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UINT: 'UINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IS: 'IS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NULL: 'NULL'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.ROW: 'ROW'>, <TokenType.ASOF: 'ASOF'>, <TokenType.CASE: 'CASE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.POINT: 'POINT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIME: 'TIME'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.INT: 'INT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TRUE: 'TRUE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.DIV: 'DIV'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FULL: 'FULL'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.ANY: 'ANY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.END: 'END'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.CUBE: 'CUBE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM: 'ENUM'>, <TokenType.XML: 'XML'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.VAR: 'VAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.APPLY: 'APPLY'>, <TokenType.SOME: 'SOME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DATE: 'DATE'>, <TokenType.INT128: 'INT128'>, <TokenType.SINK: 'SINK'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ROWS: 'ROWS'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.DELETE: 'DELETE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NAME: 'NAME'>, <TokenType.PUT: 'PUT'>, <TokenType.RENAME: 'RENAME'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.KEEP: 'KEEP'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.STAGE: 'STAGE'>, <TokenType.MAP: 'MAP'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.KILL: 'KILL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.REPLACE: 'REPLACE'>}
COLON_PLACEHOLDER_TOKENS = {<TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TOP: 'TOP'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SET: 'SET'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.JSON: 'JSON'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COPY: 'COPY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.RING: 'RING'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USE: 'USE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DESC: 'DESC'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.ASC: 'ASC'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT256: 'INT256'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INET: 'INET'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TAG: 'TAG'>, <TokenType.YEAR: 'YEAR'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.FILTER: 'FILTER'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DETACH: 'DETACH'>, <TokenType.BLOB: 'BLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LIST: 'LIST'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UINT: 'UINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IS: 'IS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NULL: 'NULL'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.ROW: 'ROW'>, <TokenType.ASOF: 'ASOF'>, <TokenType.CASE: 'CASE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.POINT: 'POINT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIME: 'TIME'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.INT: 'INT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TRUE: 'TRUE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.DIV: 'DIV'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FULL: 'FULL'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.ANY: 'ANY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.END: 'END'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.CUBE: 'CUBE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM: 'ENUM'>, <TokenType.XML: 'XML'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.VAR: 'VAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.APPLY: 'APPLY'>, <TokenType.SOME: 'SOME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DATE: 'DATE'>, <TokenType.INT128: 'INT128'>, <TokenType.SINK: 'SINK'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ROWS: 'ROWS'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.DELETE: 'DELETE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NAME: 'NAME'>, <TokenType.PUT: 'PUT'>, <TokenType.RENAME: 'RENAME'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.KEEP: 'KEEP'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.STAGE: 'STAGE'>, <TokenType.MAP: 'MAP'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.KILL: 'KILL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.REPLACE: 'REPLACE'>}
ARRAY_CONSTRUCTORS = {'ARRAY': <class 'sqlglot.expressions.Array'>, 'LIST': <class 'sqlglot.expressions.List'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TOP: 'TOP'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SET: 'SET'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.JSON: 'JSON'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COPY: 'COPY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.RING: 'RING'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USE: 'USE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DESC: 'DESC'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.ASC: 'ASC'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT256: 'INT256'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INET: 'INET'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TAG: 'TAG'>, <TokenType.YEAR: 'YEAR'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.FILTER: 'FILTER'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DETACH: 'DETACH'>, <TokenType.BLOB: 'BLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LIST: 'LIST'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UINT: 'UINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NULL: 'NULL'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.ROW: 'ROW'>, <TokenType.CASE: 'CASE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.POINT: 'POINT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIME: 'TIME'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.INT: 'INT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TRUE: 'TRUE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.DIV: 'DIV'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.FIRST: 'FIRST'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.ANY: 'ANY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.END: 'END'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.CUBE: 'CUBE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM: 'ENUM'>, <TokenType.XML: 'XML'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.VAR: 'VAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SOME: 'SOME'>, <TokenType.DATE: 'DATE'>, <TokenType.INT128: 'INT128'>, <TokenType.SINK: 'SINK'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ROWS: 'ROWS'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.DELETE: 'DELETE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NAME: 'NAME'>, <TokenType.PUT: 'PUT'>, <TokenType.RENAME: 'RENAME'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.KEEP: 'KEEP'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.STAGE: 'STAGE'>, <TokenType.MAP: 'MAP'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.KILL: 'KILL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.REPLACE: 'REPLACE'>}
UPDATE_ALIAS_TOKENS = {<TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TOP: 'TOP'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.MERGE: 'MERGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.JSON: 'JSON'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COPY: 'COPY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.RING: 'RING'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USE: 'USE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DESC: 'DESC'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.ASC: 'ASC'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT256: 'INT256'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INET: 'INET'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TAG: 'TAG'>, <TokenType.YEAR: 'YEAR'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.FILTER: 'FILTER'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DETACH: 'DETACH'>, <TokenType.BLOB: 'BLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LIST: 'LIST'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UINT: 'UINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.IS: 'IS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NULL: 'NULL'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.ROW: 'ROW'>, <TokenType.CASE: 'CASE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.POINT: 'POINT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIME: 'TIME'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.INT: 'INT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TRUE: 'TRUE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.DIV: 'DIV'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.FIRST: 'FIRST'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.ANY: 'ANY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.END: 'END'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.CUBE: 'CUBE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM: 'ENUM'>, <TokenType.XML: 'XML'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.VAR: 'VAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SOME: 'SOME'>, <TokenType.DATE: 'DATE'>, <TokenType.INT128: 'INT128'>, <TokenType.SINK: 'SINK'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ROWS: 'ROWS'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.DELETE: 'DELETE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NAME: 'NAME'>, <TokenType.PUT: 'PUT'>, <TokenType.RENAME: 'RENAME'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.KEEP: 'KEEP'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.STAGE: 'STAGE'>, <TokenType.MAP: 'MAP'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.KILL: 'KILL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.REPLACE: 'REPLACE'>}
TRIM_TYPES = {'LEADING', 'BOTH', 'TRAILING'}
FUNC_TOKENS = {<TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.JSON: 'JSON'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.GLOB: 'GLOB'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.RING: 'RING'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.INSERT: 'INSERT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.INT256: 'INT256'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INET: 'INET'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.FILTER: 'FILTER'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.BLOB: 'BLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LIST: 'LIST'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.UINT: 'UINT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NULL: 'NULL'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.ROW: 'ROW'>, <TokenType.XOR: 'XOR'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.POINT: 'POINT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIME: 'TIME'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.INT: 'INT'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.FIRST: 'FIRST'>, <TokenType.SUPER: 'SUPER'>, <TokenType.ANY: 'ANY'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM: 'ENUM'>, <TokenType.XML: 'XML'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.LIKE: 'LIKE'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.VAR: 'VAR'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SOME: 'SOME'>, <TokenType.UNION: 'UNION'>, <TokenType.DATE: 'DATE'>, <TokenType.INT128: 'INT128'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NEXT: 'NEXT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NAME: 'NAME'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.MAP: 'MAP'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.REPLACE: 'REPLACE'>}
CONJUNCTION: Dict[sqlglot.tokens.TokenType, Type[sqlglot.expressions.Expression]] = {<TokenType.AND: 'AND'>: <class 'sqlglot.expressions.And'>}
ASSIGNMENT: Dict[sqlglot.tokens.TokenType, Type[sqlglot.expressions.Expression]] = {<TokenType.COLON_EQ: 'COLON_EQ'>: <class 'sqlglot.expressions.PropertyEQ'>}
DISJUNCTION: Dict[sqlglot.tokens.TokenType, Type[sqlglot.expressions.Expression]] = {<TokenType.OR: 'OR'>: <class 'sqlglot.expressions.Or'>}
EQUALITY = {<TokenType.EQ: 'EQ'>: <class 'sqlglot.expressions.EQ'>, <TokenType.NEQ: 'NEQ'>: <class 'sqlglot.expressions.NEQ'>, <TokenType.NULLSAFE_EQ: 'NULLSAFE_EQ'>: <class 'sqlglot.expressions.NullSafeEQ'>}
COMPARISON = {<TokenType.GT: 'GT'>: <class 'sqlglot.expressions.GT'>, <TokenType.GTE: 'GTE'>: <class 'sqlglot.expressions.GTE'>, <TokenType.LT: 'LT'>: <class 'sqlglot.expressions.LT'>, <TokenType.LTE: 'LTE'>: <class 'sqlglot.expressions.LTE'>}
BITWISE = {<TokenType.AMP: 'AMP'>: <class 'sqlglot.expressions.BitwiseAnd'>, <TokenType.CARET: 'CARET'>: <class 'sqlglot.expressions.BitwiseXor'>, <TokenType.PIPE: 'PIPE'>: <class 'sqlglot.expressions.BitwiseOr'>}
TERM = {<TokenType.DASH: 'DASH'>: <class 'sqlglot.expressions.Sub'>, <TokenType.PLUS: 'PLUS'>: <class 'sqlglot.expressions.Add'>, <TokenType.MOD: 'MOD'>: <class 'sqlglot.expressions.Mod'>, <TokenType.COLLATE: 'COLLATE'>: <class 'sqlglot.expressions.Collate'>}
FACTOR = {<TokenType.DIV: 'DIV'>: <class 'sqlglot.expressions.IntDiv'>, <TokenType.LR_ARROW: 'LR_ARROW'>: <class 'sqlglot.expressions.Distance'>, <TokenType.SLASH: 'SLASH'>: <class 'sqlglot.expressions.Div'>, <TokenType.STAR: 'STAR'>: <class 'sqlglot.expressions.Mul'>}
EXPONENT: Dict[sqlglot.tokens.TokenType, Type[sqlglot.expressions.Expression]] = {}
TIMES = {<TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIME: 'TIME'>}
TIMESTAMPS = {<TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>}
SET_OPERATIONS = {<TokenType.INTERSECT: 'INTERSECT'>, <TokenType.EXCEPT: 'EXCEPT'>, <TokenType.UNION: 'UNION'>}
JOIN_METHODS = {<TokenType.POSITIONAL: 'POSITIONAL'>, <TokenType.ASOF: 'ASOF'>, <TokenType.NATURAL: 'NATURAL'>}
JOIN_SIDES = {<TokenType.LEFT: 'LEFT'>, <TokenType.FULL: 'FULL'>, <TokenType.RIGHT: 'RIGHT'>}
JOIN_KINDS = {<TokenType.STRAIGHT_JOIN: 'STRAIGHT_JOIN'>, <TokenType.INNER: 'INNER'>, <TokenType.ANTI: 'ANTI'>, <TokenType.CROSS: 'CROSS'>, <TokenType.SEMI: 'SEMI'>, <TokenType.OUTER: 'OUTER'>}
JOIN_HINTS: Set[str] = set()
LAMBDAS = {<TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.FARROW: 'FARROW'>: <function Parser.<lambda>>}
COLUMN_OPERATORS = {<TokenType.DOT: 'DOT'>: None, <TokenType.DOTCOLON: 'DOTCOLON'>: <function Parser.<lambda>>, <TokenType.DCOLON: 'DCOLON'>: <function Parser.<lambda>>, <TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.DARROW: 'DARROW'>: <function Parser.<lambda>>, <TokenType.HASH_ARROW: 'HASH_ARROW'>: <function Parser.<lambda>>, <TokenType.DHASH_ARROW: 'DHASH_ARROW'>: <function Parser.<lambda>>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>}
EXPRESSION_PARSERS = {<class 'sqlglot.expressions.Cluster'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Column'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Condition'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.DataType'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Expression'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.From'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Group'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Having'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Hint'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Identifier'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Join'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lambda'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lateral'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Limit'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Offset'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Order'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Ordered'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Properties'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.PartitionedByProperty'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Qualify'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Returning'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Select'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Sort'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Table'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.TableAlias'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Tuple'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Whens'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Where'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Window'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.With'>: <function Parser.<lambda>>, 'JOIN_TYPE': <function Parser.<lambda>>}
STATEMENT_PARSERS = {<TokenType.ALTER: 'ALTER'>: <function Parser.<lambda>>, <TokenType.ANALYZE: 'ANALYZE'>: <function Parser.<lambda>>, <TokenType.BEGIN: 'BEGIN'>: <function Parser.<lambda>>, <TokenType.CACHE: 'CACHE'>: <function Parser.<lambda>>, <TokenType.COMMENT: 'COMMENT'>: <function Parser.<lambda>>, <TokenType.COMMIT: 'COMMIT'>: <function Parser.<lambda>>, <TokenType.COPY: 'COPY'>: <function Parser.<lambda>>, <TokenType.CREATE: 'CREATE'>: <function Parser.<lambda>>, <TokenType.DELETE: 'DELETE'>: <function Parser.<lambda>>, <TokenType.DESC: 'DESC'>: <function Parser.<lambda>>, <TokenType.DESCRIBE: 'DESCRIBE'>: <function Parser.<lambda>>, <TokenType.DROP: 'DROP'>: <function Parser.<lambda>>, <TokenType.GRANT: 'GRANT'>: <function Parser.<lambda>>, <TokenType.INSERT: 'INSERT'>: <function Parser.<lambda>>, <TokenType.KILL: 'KILL'>: <function Parser.<lambda>>, <TokenType.LOAD: 'LOAD'>: <function Parser.<lambda>>, <TokenType.MERGE: 'MERGE'>: <function Parser.<lambda>>, <TokenType.PIVOT: 'PIVOT'>: <function Parser.<lambda>>, <TokenType.PRAGMA: 'PRAGMA'>: <function Parser.<lambda>>, <TokenType.REFRESH: 'REFRESH'>: <function Parser.<lambda>>, <TokenType.ROLLBACK: 'ROLLBACK'>: <function Parser.<lambda>>, <TokenType.SET: 'SET'>: <function Parser.<lambda>>, <TokenType.TRUNCATE: 'TRUNCATE'>: <function Parser.<lambda>>, <TokenType.UNCACHE: 'UNCACHE'>: <function Parser.<lambda>>, <TokenType.UNPIVOT: 'UNPIVOT'>: <function Parser.<lambda>>, <TokenType.UPDATE: 'UPDATE'>: <function Parser.<lambda>>, <TokenType.USE: 'USE'>: <function Parser.<lambda>>, <TokenType.SEMICOLON: 'SEMICOLON'>: <function Parser.<lambda>>}
UNARY_PARSERS = {<TokenType.PLUS: 'PLUS'>: <function Parser.<lambda>>, <TokenType.NOT: 'NOT'>: <function Parser.<lambda>>, <TokenType.TILDA: 'TILDA'>: <function Parser.<lambda>>, <TokenType.DASH: 'DASH'>: <function Parser.<lambda>>, <TokenType.PIPE_SLASH: 'PIPE_SLASH'>: <function Parser.<lambda>>, <TokenType.DPIPE_SLASH: 'DPIPE_SLASH'>: <function Parser.<lambda>>}
STRING_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>}
NUMERIC_PARSERS = {<TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>}
PRIMARY_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>, <TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>, <TokenType.INTRODUCER: 'INTRODUCER'>: <function Parser.<lambda>>, <TokenType.NULL: 'NULL'>: <function Parser.<lambda>>, <TokenType.TRUE: 'TRUE'>: <function Parser.<lambda>>, <TokenType.FALSE: 'FALSE'>: <function Parser.<lambda>>, <TokenType.SESSION_PARAMETER: 'SESSION_PARAMETER'>: <function Parser.<lambda>>, <TokenType.STAR: 'STAR'>: <function Parser.<lambda>>}
PLACEHOLDER_PARSERS = {<TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>, <TokenType.PARAMETER: 'PARAMETER'>: <function Parser.<lambda>>, <TokenType.COLON: 'COLON'>: <function Parser.<lambda>>}
RANGE_PARSERS = {<TokenType.AT_GT: 'AT_GT'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.BETWEEN: 'BETWEEN'>: <function Parser.<lambda>>, <TokenType.GLOB: 'GLOB'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.ILIKE: 'ILIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.IN: 'IN'>: <function Parser.<lambda>>, <TokenType.IRLIKE: 'IRLIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.IS: 'IS'>: <function Parser.<lambda>>, <TokenType.LIKE: 'LIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.LT_AT: 'LT_AT'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.OVERLAPS: 'OVERLAPS'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.RLIKE: 'RLIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.SIMILAR_TO: 'SIMILAR_TO'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>}
PROPERTY_PARSERS: Dict[str, Callable] = {'ALLOWED_VALUES': <function Parser.<lambda>>, 'ALGORITHM': <function Parser.<lambda>>, 'AUTO': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'BACKUP': <function Parser.<lambda>>, 'BLOCKCOMPRESSION': <function Parser.<lambda>>, 'CHARSET': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECKSUM': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'CONTAINS': <function Parser.<lambda>>, 'COPY': <function Parser.<lambda>>, 'DATABLOCKSIZE': <function Parser.<lambda>>, 'DATA_DELETION': <function Parser.<lambda>>, 'DEFINER': <function Parser.<lambda>>, 'DETERMINISTIC': <function Parser.<lambda>>, 'DISTRIBUTED': <function Parser.<lambda>>, 'DUPLICATE': <function Parser.<lambda>>, 'DYNAMIC': <function Parser.<lambda>>, 'DISTKEY': <function Parser.<lambda>>, 'DISTSTYLE': <function Parser.<lambda>>, 'EMPTY': <function Parser.<lambda>>, 'ENGINE': <function Parser.<lambda>>, 'EXECUTE': <function Parser.<lambda>>, 'EXTERNAL': <function Parser.<lambda>>, 'FALLBACK': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'FREESPACE': <function Parser.<lambda>>, 'GLOBAL': <function Parser.<lambda>>, 'HEAP': <function Parser.<lambda>>, 'ICEBERG': <function Parser.<lambda>>, 'IMMUTABLE': <function Parser.<lambda>>, 'INHERITS': <function Parser.<lambda>>, 'INPUT': <function Parser.<lambda>>, 'JOURNAL': <function Parser.<lambda>>, 'LANGUAGE': <function Parser.<lambda>>, 'LAYOUT': <function Parser.<lambda>>, 'LIFETIME': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'LOCATION': <function Parser.<lambda>>, 'LOCK': <function Parser.<lambda>>, 'LOCKING': <function Parser.<lambda>>, 'LOG': <function Parser.<lambda>>, 'MATERIALIZED': <function Parser.<lambda>>, 'MERGEBLOCKRATIO': <function Parser.<lambda>>, 'MODIFIES': <function Parser.<lambda>>, 'MULTISET': <function Parser.<lambda>>, 'NO': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'ORDER BY': <function Parser.<lambda>>, 'OUTPUT': <function Parser.<lambda>>, 'PARTITION': <function Parser.<lambda>>, 'PARTITION BY': <function Parser.<lambda>>, 'PARTITIONED BY': <function Parser.<lambda>>, 'PARTITIONED_BY': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'RANGE': <function Parser.<lambda>>, 'READS': <function Parser.<lambda>>, 'REMOTE': <function Parser.<lambda>>, 'RETURNS': <function Parser.<lambda>>, 'STRICT': <function Parser.<lambda>>, 'STREAMING': <function Parser.<lambda>>, 'ROW': <function Parser.<lambda>>, 'ROW_FORMAT': <function Parser.<lambda>>, 'SAMPLE': <function Parser.<lambda>>, 'SECURE': <function Parser.<lambda>>, 'SECURITY': <function Parser.<lambda>>, 'SET': <function Parser.<lambda>>, 'SETTINGS': <function Parser.<lambda>>, 'SHARING': <function Parser.<lambda>>, 'SORTKEY': <function Parser.<lambda>>, 'SOURCE': <function Parser.<lambda>>, 'STABLE': <function Parser.<lambda>>, 'STORED': <function Parser.<lambda>>, 'SYSTEM_VERSIONING': <function Parser.<lambda>>, 'TBLPROPERTIES': <function Parser.<lambda>>, 'TEMP': <function Parser.<lambda>>, 'TEMPORARY': <function Parser.<lambda>>, 'TO': <function Parser.<lambda>>, 'TRANSIENT': <function Parser.<lambda>>, 'TRANSFORM': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'USING': <function Parser.<lambda>>, 'UNLOGGED': <function Parser.<lambda>>, 'VOLATILE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
CONSTRAINT_PARSERS = {'AUTOINCREMENT': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'CASESPECIFIC': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECK': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'COMPRESS': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'NONCLUSTERED': <function Parser.<lambda>>, 'DEFAULT': <function Parser.<lambda>>, 'ENCODE': <function Parser.<lambda>>, 'EPHEMERAL': <function Parser.<lambda>>, 'EXCLUDE': <function Parser.<lambda>>, 'FOREIGN KEY': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'GENERATED': <function Parser.<lambda>>, 'IDENTITY': <function Parser.<lambda>>, 'INLINE': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'NOT': <function Parser.<lambda>>, 'NULL': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'PATH': <function Parser.<lambda>>, 'PERIOD': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'REFERENCES': <function Parser.<lambda>>, 'TITLE': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'UNIQUE': <function Parser.<lambda>>, 'UPPERCASE': <function Parser.<lambda>>, 'WATERMARK': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>, 'BUCKET': <function Parser.<lambda>>, 'TRUNCATE': <function Parser.<lambda>>}
ALTER_PARSERS = {'ADD': <function Parser.<lambda>>, 'AS': <function Parser.<lambda>>, 'ALTER': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'RENAME': <function Parser.<lambda>>, 'SET': <function Parser.<lambda>>, 'SWAP': <function Parser.<lambda>>}
ALTER_ALTER_PARSERS = {'DISTKEY': <function Parser.<lambda>>, 'DISTSTYLE': <function Parser.<lambda>>, 'SORTKEY': <function Parser.<lambda>>, 'COMPOUND': <function Parser.<lambda>>}
SCHEMA_UNNAMED_CONSTRAINTS = {'CHECK', 'PRIMARY KEY', 'PERIOD', 'BUCKET', 'LIKE', 'FOREIGN KEY', 'WATERMARK', 'UNIQUE', 'TRUNCATE', 'EXCLUDE'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STRING: 'STRING'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
KEY_VALUE_DEFINITIONS = (<class 'sqlglot.expressions.Alias'>, <class 'sqlglot.expressions.EQ'>, <class 'sqlglot.expressions.PropertyEQ'>, <class 'sqlglot.expressions.Slice'>)
FUNCTION_PARSERS = {'CAST': <function Parser.<lambda>>, 'CEIL': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'FLOOR': <function Parser.<lambda>>, 'GAP_FILL': <function Parser.<lambda>>, 'JSON_OBJECT': <function Parser.<lambda>>, 'JSON_OBJECTAGG': <function Parser.<lambda>>, 'JSON_TABLE': <function Parser.<lambda>>, 'MATCH': <function Parser.<lambda>>, 'NORMALIZE': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'OVERLAY': <function Parser.<lambda>>, 'POSITION': <function Parser.<lambda>>, 'PREDICT': <function Parser.<lambda>>, 'SAFE_CAST': <function Parser.<lambda>>, 'STRING_AGG': <function Parser.<lambda>>, 'SUBSTRING': <function Parser.<lambda>>, 'TRIM': <function Parser.<lambda>>, 'TRY_CAST': <function Parser.<lambda>>, 'TRY_CONVERT': <function Parser.<lambda>>, 'XMLELEMENT': <function Parser.<lambda>>, 'XMLTABLE': <function Parser.<lambda>>}
QUERY_MODIFIER_PARSERS = {<TokenType.MATCH_RECOGNIZE: 'MATCH_RECOGNIZE'>: <function Parser.<lambda>>, <TokenType.PREWHERE: 'PREWHERE'>: <function Parser.<lambda>>, <TokenType.WHERE: 'WHERE'>: <function Parser.<lambda>>, <TokenType.GROUP_BY: 'GROUP_BY'>: <function Parser.<lambda>>, <TokenType.HAVING: 'HAVING'>: <function Parser.<lambda>>, <TokenType.QUALIFY: 'QUALIFY'>: <function Parser.<lambda>>, <TokenType.WINDOW: 'WINDOW'>: <function Parser.<lambda>>, <TokenType.ORDER_BY: 'ORDER_BY'>: <function Parser.<lambda>>, <TokenType.LIMIT: 'LIMIT'>: <function Parser.<lambda>>, <TokenType.FETCH: 'FETCH'>: <function Parser.<lambda>>, <TokenType.OFFSET: 'OFFSET'>: <function Parser.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>, <TokenType.LOCK: 'LOCK'>: <function Parser.<lambda>>, <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>: <function Parser.<lambda>>, <TokenType.USING: 'USING'>: <function Parser.<lambda>>, <TokenType.CLUSTER_BY: 'CLUSTER_BY'>: <function Parser.<lambda>>, <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>: <function Parser.<lambda>>, <TokenType.SORT_BY: 'SORT_BY'>: <function Parser.<lambda>>, <TokenType.CONNECT_BY: 'CONNECT_BY'>: <function Parser.<lambda>>, <TokenType.START_WITH: 'START_WITH'>: <function Parser.<lambda>>}
SET_PARSERS = {'GLOBAL': <function Parser.<lambda>>, 'LOCAL': <function Parser.<lambda>>, 'SESSION': <function Parser.<lambda>>, 'TRANSACTION': <function Parser.<lambda>>}
SHOW_PARSERS: Dict[str, Callable] = {}
TYPE_LITERAL_PARSERS = {<Type.JSON: 'JSON'>: <function Parser.<lambda>>}
TYPE_CONVERTERS: Dict[sqlglot.expressions.DataType.Type, Callable[[sqlglot.expressions.DataType], sqlglot.expressions.DataType]] = {}
DDL_SELECT_TOKENS = {<TokenType.WITH: 'WITH'>, <TokenType.SELECT: 'SELECT'>, <TokenType.L_PAREN: 'L_PAREN'>}
PRE_VOLATILE_TOKENS = {<TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CREATE: 'CREATE'>, <TokenType.REPLACE: 'REPLACE'>}
TRANSACTION_KIND = {'DEFERRED', 'EXCLUSIVE', 'IMMEDIATE'}
TRANSACTION_CHARACTERISTICS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ISOLATION': (('LEVEL', 'REPEATABLE', 'READ'), ('LEVEL', 'READ', 'COMMITTED'), ('LEVEL', 'READ', 'UNCOMITTED'), ('LEVEL', 'SERIALIZABLE')), 'READ': ('WRITE', 'ONLY')}
CONFLICT_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ABORT': (), 'FAIL': (), 'IGNORE': (), 'REPLACE': (), 'ROLLBACK': (), 'UPDATE': (), 'DO': ('NOTHING', 'UPDATE')}
CREATE_SEQUENCE: Dict[str, Sequence[Union[Sequence[str], str]]] = {'SCALE': ('EXTEND', 'NOEXTEND'), 'SHARD': ('EXTEND', 'NOEXTEND'), 'NO': ('CYCLE', 'CACHE', 'MAXVALUE', 'MINVALUE'), 'SESSION': (), 'GLOBAL': (), 'KEEP': (), 'NOKEEP': (), 'ORDER': (), 'NOORDER': (), 'NOCACHE': (), 'CYCLE': (), 'NOCYCLE': (), 'NOMINVALUE': (), 'NOMAXVALUE': (), 'NOSCALE': (), 'NOSHARD': ()}
ISOLATED_LOADING_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'FOR': ('ALL', 'INSERT', 'NONE')}
USABLES: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ROLE': (), 'WAREHOUSE': (), 'DATABASE': (), 'SCHEMA': (), 'CATALOG': ()}
CAST_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'RENAME': ('FIELDS',), 'ADD': ('FIELDS',)}
SCHEMA_BINDING_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'TYPE': ('EVOLUTION',), 'BINDING': (), 'COMPENSATION': (), 'EVOLUTION': ()}
PROCEDURE_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {}
EXECUTE_AS_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'CALLER': (), 'SELF': (), 'OWNER': ()}
KEY_CONSTRAINT_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'NOT': ('ENFORCED',), 'MATCH': ('FULL', 'PARTIAL', 'SIMPLE'), 'INITIALLY': ('DEFERRED', 'IMMEDIATE'), 'USING': ('BTREE', 'HASH'), 'DEFERRABLE': (), 'NORELY': (), 'RELY': ()}
INSERT_ALTERNATIVES = {'IGNORE', 'ROLLBACK', 'FAIL', 'REPLACE', 'ABORT'}
CLONE_KEYWORDS = {'COPY', 'CLONE'}
HISTORICAL_DATA_PREFIX = {'BEFORE', 'AT', 'END'}
HISTORICAL_DATA_KIND = {'STREAM', 'TIMESTAMP', 'STATEMENT', 'OFFSET'}
OPCLASS_FOLLOW_KEYWORDS = {'ASC', 'WITH', 'NULLS', 'DESC'}
OPTYPE_FOLLOW_TOKENS = {<TokenType.COMMA: 'COMMA'>, <TokenType.R_PAREN: 'R_PAREN'>}
TABLE_INDEX_HINT_TOKENS = {<TokenType.IGNORE: 'IGNORE'>, <TokenType.FORCE: 'FORCE'>, <TokenType.USE: 'USE'>}
VIEW_ATTRIBUTES = {'ENCRYPTION', 'VIEW_METADATA', 'SCHEMABINDING'}
WINDOW_ALIAS_TOKENS = {<TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TOP: 'TOP'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SET: 'SET'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.JSON: 'JSON'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COPY: 'COPY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.RING: 'RING'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USE: 'USE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DESC: 'DESC'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.ASC: 'ASC'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT256: 'INT256'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INET: 'INET'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TAG: 'TAG'>, <TokenType.YEAR: 'YEAR'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.FILTER: 'FILTER'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DETACH: 'DETACH'>, <TokenType.BLOB: 'BLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LIST: 'LIST'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UINT: 'UINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IS: 'IS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NULL: 'NULL'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.ROW: 'ROW'>, <TokenType.ASOF: 'ASOF'>, <TokenType.CASE: 'CASE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.POINT: 'POINT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIME: 'TIME'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.INT: 'INT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TRUE: 'TRUE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.DIV: 'DIV'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FULL: 'FULL'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.ANY: 'ANY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.END: 'END'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.CUBE: 'CUBE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM: 'ENUM'>, <TokenType.XML: 'XML'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.VAR: 'VAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.APPLY: 'APPLY'>, <TokenType.SOME: 'SOME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DATE: 'DATE'>, <TokenType.INT128: 'INT128'>, <TokenType.SINK: 'SINK'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.DELETE: 'DELETE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NAME: 'NAME'>, <TokenType.PUT: 'PUT'>, <TokenType.RENAME: 'RENAME'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.KEEP: 'KEEP'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.STAGE: 'STAGE'>, <TokenType.MAP: 'MAP'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.KILL: 'KILL'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.REPLACE: 'REPLACE'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'PRECEDING', 'FOLLOWING'}
JSON_KEY_VALUE_SEPARATOR_TOKENS = {<TokenType.COLON: 'COLON'>, <TokenType.COMMA: 'COMMA'>, <TokenType.IS: 'IS'>}
FETCH_TOKENS = {<TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TOP: 'TOP'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SET: 'SET'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.JSON: 'JSON'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COPY: 'COPY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.RING: 'RING'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USE: 'USE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DESC: 'DESC'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.ASC: 'ASC'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT256: 'INT256'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INET: 'INET'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TAG: 'TAG'>, <TokenType.YEAR: 'YEAR'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.FILTER: 'FILTER'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DETACH: 'DETACH'>, <TokenType.BLOB: 'BLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LIST: 'LIST'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UINT: 'UINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IS: 'IS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NULL: 'NULL'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.ASOF: 'ASOF'>, <TokenType.CASE: 'CASE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.POINT: 'POINT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIME: 'TIME'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.INT: 'INT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TRUE: 'TRUE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.DIV: 'DIV'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FULL: 'FULL'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.ANY: 'ANY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.END: 'END'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.CUBE: 'CUBE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM: 'ENUM'>, <TokenType.XML: 'XML'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.VAR: 'VAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.APPLY: 'APPLY'>, <TokenType.SOME: 'SOME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DATE: 'DATE'>, <TokenType.INT128: 'INT128'>, <TokenType.SINK: 'SINK'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.DELETE: 'DELETE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NAME: 'NAME'>, <TokenType.PUT: 'PUT'>, <TokenType.RENAME: 'RENAME'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.KEEP: 'KEEP'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.STAGE: 'STAGE'>, <TokenType.MAP: 'MAP'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.KILL: 'KILL'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.REPLACE: 'REPLACE'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.KEY: 'KEY'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TOP: 'TOP'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SET: 'SET'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.JSON: 'JSON'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.COPY: 'COPY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.RING: 'RING'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.USE: 'USE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DESC: 'DESC'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.ASC: 'ASC'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT256: 'INT256'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.INET: 'INET'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TAG: 'TAG'>, <TokenType.YEAR: 'YEAR'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FINAL: 'FINAL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.FILTER: 'FILTER'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DETACH: 'DETACH'>, <TokenType.BLOB: 'BLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LIST: 'LIST'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.FALSE: 'FALSE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UINT: 'UINT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TEXT: 'TEXT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.IS: 'IS'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.NULL: 'NULL'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UINT256: 'UINT256'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.ROW: 'ROW'>, <TokenType.CASE: 'CASE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.POINT: 'POINT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TIME: 'TIME'>, <TokenType.NESTED: 'NESTED'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.INT: 'INT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TRUE: 'TRUE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.DIV: 'DIV'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.FIRST: 'FIRST'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.ANY: 'ANY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.END: 'END'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.CUBE: 'CUBE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.BIT: 'BIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ENUM: 'ENUM'>, <TokenType.XML: 'XML'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.VAR: 'VAR'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SOME: 'SOME'>, <TokenType.DATE: 'DATE'>, <TokenType.INT128: 'INT128'>, <TokenType.SINK: 'SINK'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ROWS: 'ROWS'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.SHOW: 'SHOW'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.DELETE: 'DELETE'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NAME: 'NAME'>, <TokenType.PUT: 'PUT'>, <TokenType.RENAME: 'RENAME'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.KEEP: 'KEEP'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.STAGE: 'STAGE'>, <TokenType.MAP: 'MAP'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.KILL: 'KILL'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.REPLACE: 'REPLACE'>}
SELECT_START_TOKENS = {<TokenType.WITH: 'WITH'>, <TokenType.SELECT: 'SELECT'>, <TokenType.L_PAREN: 'L_PAREN'>}
COPY_INTO_VARLEN_OPTIONS = {'COPY_OPTIONS', 'FORMAT_OPTIONS', 'FILE_FORMAT', 'CREDENTIAL'}
IS_JSON_PREDICATE_KIND = {'ARRAY', 'OBJECT', 'SCALAR', 'VALUE'}
ODBC_DATETIME_LITERALS = {'d': <class 'sqlglot.expressions.Date'>, 't': <class 'sqlglot.expressions.Time'>, 'ts': <class 'sqlglot.expressions.Timestamp'>}
ON_CONDITION_TOKENS = {'EMPTY', 'FALSE', 'NULL', 'ERROR', 'TRUE'}
PRIVILEGE_FOLLOW_TOKENS = {<TokenType.ON: 'ON'>, <TokenType.COMMA: 'COMMA'>, <TokenType.L_PAREN: 'L_PAREN'>}
DESCRIBE_STYLES = {'FORMATTED', 'EXTENDED', 'ANALYZE', 'HISTORY'}
ANALYZE_STYLES = {'SAMPLE', 'SKIP_LOCKED', 'LOCAL', 'NO_WRITE_TO_BINLOG', 'BUFFER_USAGE_LIMIT', 'VERBOSE', 'FULL'}
ANALYZE_EXPRESSION_PARSERS = {'ALL': <function Parser.<lambda>>, 'COMPUTE': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'ESTIMATE': <function Parser.<lambda>>, 'LIST': <function Parser.<lambda>>, 'PREDICATE': <function Parser.<lambda>>, 'UPDATE': <function Parser.<lambda>>, 'VALIDATE': <function Parser.<lambda>>}
PARTITION_KEYWORDS = {'PARTITION', 'SUBPARTITION'}
AMBIGUOUS_ALIAS_TOKENS = (<TokenType.LIMIT: 'LIMIT'>, <TokenType.OFFSET: 'OFFSET'>)
OPERATION_MODIFIERS: Set[str] = set()
RECURSIVE_CTE_SEARCH_KIND = {'CYCLE', 'DEPTH', 'BREADTH'}
MODIFIABLES = (<class 'sqlglot.expressions.Query'>, <class 'sqlglot.expressions.Table'>, <class 'sqlglot.expressions.TableFromRows'>)
STRICT_CAST = True
PREFIXED_PIVOT_COLUMNS = False
IDENTIFY_PIVOT_STRINGS = False
LOG_DEFAULTS_TO_LN = False
ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
TABLESAMPLE_CSV = False
DEFAULT_SAMPLING_METHOD: Optional[str] = None
SET_REQUIRES_ASSIGNMENT_DELIMITER = True
TRIM_PATTERN_FIRST = False
STRING_ALIASES = False
MODIFIERS_ATTACHED_TO_SET_OP = True
SET_OP_MODIFIERS = {'limit', 'order', 'offset'}
NO_PAREN_IF_COMMANDS = True
JSON_ARROWS_REQUIRE_JSON_TYPE = False
COLON_IS_VARIANT_EXTRACT = False
VALUES_FOLLOWED_BY_PAREN = True
SUPPORTS_IMPLICIT_UNNEST = False
INTERVAL_SPANS = True
SUPPORTS_PARTITION_SELECTION = False
WRAPPED_TRANSFORM_COLUMN_CONSTRAINT = True
OPTIONAL_ALIAS_TOKEN_CTE = True
SHOW_TRIE: Dict = {}
SET_TRIE: Dict = {'GLOBAL': {0: True}, 'LOCAL': {0: True}, 'SESSION': {0: True}, 'TRANSACTION': {0: True}}
error_level
error_message_context
max_errors
dialect
def reset(self): View Source

    1517    def reset(self):
    1518        self.sql = ""
    1519        self.errors = []
    1520        self._tokens = []
    1521        self._index = 0
    1522        self._curr = None
    1523        self._next = None
    1524        self._prev = None
    1525        self._prev_comments = None

def parse( self, raw_tokens: List[sqlglot.tokens.Token], sql: Optional[str] = None) -> List[Optional[sqlglot.expressions.Expression]]: View Source

    1527    def parse(
    1528        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    1529    ) -> t.List[t.Optional[exp.Expression]]:
    1530        """
    1531        Parses a list of tokens and returns a list of syntax trees, one tree
    1532        per parsed SQL statement.
    1533
    1534        Args:
    1535            raw_tokens: The list of tokens.
    1536            sql: The original SQL string, used to produce helpful debug messages.
    1537
    1538        Returns:
    1539            The list of the produced syntax trees.
    1540        """
    1541        return self._parse(
    1542            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    1543        )

Parses a list of tokens and returns a list of syntax trees, one tree per parsed SQL statement.

###### Arguments:

- raw_tokens: The list of tokens.
- sql: The original SQL string, used to produce helpful debug messages.

###### Returns:

> The list of the produced syntax trees.

def parse_into( self, expression_types: Union[str, Type[sqlglot.expressions.Expression], Collection[Union[str, Type[sqlglot.expressions.Expression]]]], raw_tokens: List[sqlglot.tokens.Token], sql: Optional[str] = None) -> List[Optional[sqlglot.expressions.Expression]]: View Source

    1545    def parse_into(
    1546        self,
    1547        expression_types: exp.IntoType,
    1548        raw_tokens: t.List[Token],
    1549        sql: t.Optional[str] = None,
    1550    ) -> t.List[t.Optional[exp.Expression]]:
    1551        """
    1552        Parses a list of tokens into a given Expression type. If a collection of Expression
    1553        types is given instead, this method will try to parse the token list into each one
    1554        of them, stopping at the first for which the parsing succeeds.
    1555
    1556        Args:
    1557            expression_types: The expression type(s) to try and parse the token list into.
    1558            raw_tokens: The list of tokens.
    1559            sql: The original SQL string, used to produce helpful debug messages.
    1560
    1561        Returns:
    1562            The target Expression.
    1563        """
    1564        errors = []
    1565        for expression_type in ensure_list(expression_types):
    1566            parser = self.EXPRESSION_PARSERS.get(expression_type)
    1567            if not parser:
    1568                raise TypeError(f"No parser registered for {expression_type}")
    1569
    1570            try:
    1571                return self._parse(parser, raw_tokens, sql)
    1572            except ParseError as e:
    1573                e.errors[0]["into_expression"] = expression_type
    1574                errors.append(e)
    1575
    1576        raise ParseError(
    1577            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    1578            errors=merge_errors(errors),
    1579        ) from errors[-1]

Parses a list of tokens into a given Expression type. If a collection of Expression types is given instead, this method will try to parse the token list into each one of them, stopping at the first for which the parsing succeeds.

###### Arguments:

- expression_types: The expression type(s) to try and parse the token list into.
- raw_tokens: The list of tokens.
- sql: The original SQL string, used to produce helpful debug messages.

###### Returns:

> The target Expression.

def check_errors(self) -> None: View Source

    1619    def check_errors(self) -> None:
    1620        """Logs or raises any found errors, depending on the chosen error level setting."""
    1621        if self.error_level == ErrorLevel.WARN:
    1622            for error in self.errors:
    1623                logger.error(str(error))
    1624        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1625            raise ParseError(
    1626                concat_messages(self.errors, self.max_errors),
    1627                errors=merge_errors(self.errors),
    1628            )

Logs or raises any found errors, depending on the chosen error level setting.

def raise_error(self, message: str, token: Optional[sqlglot.tokens.Token] = None) -> None: View Source

    1630    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1631        """
    1632        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1633        error level setting.
    1634        """
    1635        token = token or self._curr or self._prev or Token.string("")
    1636        start = token.start
    1637        end = token.end + 1
    1638        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1639        highlight = self.sql[start:end]
    1640        end_context = self.sql[end : end + self.error_message_context]
    1641
    1642        error = ParseError.new(
    1643            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1644            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1645            description=message,
    1646            line=token.line,
    1647            col=token.col,
    1648            start_context=start_context,
    1649            highlight=highlight,
    1650            end_context=end_context,
    1651        )
    1652
    1653        if self.error_level == ErrorLevel.IMMEDIATE:
    1654            raise error
    1655
    1656        self.errors.append(error)

Appends an error in the list of recorded errors or raises it, depending on the chosen error level setting.

def expression( self, exp_class: Type[~E], comments: Optional[List[str]] = None, **kwargs) -> ~E: View Source

    1658    def expression(
    1659        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1660    ) -> E:
    1661        """
    1662        Creates a new, validated Expression.
    1663
    1664        Args:
    1665            exp_class: The expression class to instantiate.
    1666            comments: An optional list of comments to attach to the expression.
    1667            kwargs: The arguments to set for the expression along with their respective values.
    1668
    1669        Returns:
    1670            The target expression.
    1671        """
    1672        instance = exp_class(**kwargs)
    1673        instance.add_comments(comments) if comments else self._add_comments(instance)
    1674        return self.validate_expression(instance)

Creates a new, validated Expression.

###### Arguments:

- exp_class: The expression class to instantiate.
- comments: An optional list of comments to attach to the expression.
- kwargs: The arguments to set for the expression along with their respective values.

###### Returns:

> The target expression.

def validate_expression(self, expression: ~E, args: Optional[List] = None) -> ~E: View Source

    1681    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1682        """
    1683        Validates an Expression, making sure that all its mandatory arguments are set.
    1684
    1685        Args:
    1686            expression: The expression to validate.
    1687            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1688
    1689        Returns:
    1690            The validated expression.
    1691        """
    1692        if self.error_level != ErrorLevel.IGNORE:
    1693            for error_message in expression.error_messages(args):
    1694                self.raise_error(error_message)
    1695
    1696        return expression

Validates an Expression, making sure that all its mandatory arguments are set.

###### Arguments:

- expression: The expression to validate.
- args: An optional list of items that was used to instantiate the expression, if it's a Func.

###### Returns:

> The validated expression.

def parse_set_operation( self, this: Optional[sqlglot.expressions.Expression]) -> Optional[sqlglot.expressions.Expression]: View Source

    4663    def parse_set_operation(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4664        start = self._index
    4665        _, side_token, kind_token = self._parse_join_parts()
    4666
    4667        side = side_token.text if side_token else None
    4668        kind = kind_token.text if kind_token else None
    4669
    4670        if not self._match_set(self.SET_OPERATIONS):
    4671            self._retreat(start)
    4672            return None
    4673
    4674        token_type = self._prev.token_type
    4675
    4676        if token_type == TokenType.UNION:
    4677            operation: t.Type[exp.SetOperation] = exp.Union
    4678        elif token_type == TokenType.EXCEPT:
    4679            operation = exp.Except
    4680        else:
    4681            operation = exp.Intersect
    4682
    4683        comments = self._prev.comments
    4684
    4685        if self._match(TokenType.DISTINCT):
    4686            distinct: t.Optional[bool] = True
    4687        elif self._match(TokenType.ALL):
    4688            distinct = False
    4689        else:
    4690            distinct = self.dialect.SET_OP_DISTINCT_BY_DEFAULT[operation]
    4691            if distinct is None:
    4692                self.raise_error(f"Expected DISTINCT or ALL for {operation.__name__}")
    4693
    4694        by_name = self._match_text_seq("BY", "NAME") or self._match_text_seq(
    4695            "STRICT", "CORRESPONDING"
    4696        )
    4697        if self._match_text_seq("CORRESPONDING"):
    4698            by_name = True
    4699            if not side and not kind:
    4700                kind = "INNER"
    4701
    4702        on_column_list = None
    4703        if by_name and self._match_texts(("ON", "BY")):
    4704            on_column_list = self._parse_wrapped_csv(self._parse_column)
    4705
    4706        expression = self._parse_select(nested=True, parse_set_operation=False)
    4707
    4708        return self.expression(
    4709            operation,
    4710            comments=comments,
    4711            this=this,
    4712            distinct=distinct,
    4713            by_name=by_name,
    4714            expression=expression,
    4715            side=side,
    4716            kind=kind,
    4717            on=on_column_list,
    4718        )

errors
sql