sqlglot.parser API documentation

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

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

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

    1511    def __init__(
    1512        self,
    1513        error_level: t.Optional[ErrorLevel] = None,
    1514        error_message_context: int = 100,
    1515        max_errors: int = 3,
    1516        dialect: DialectType = None,
    1517    ):
    1518        from sqlglot.dialects import Dialect
    1519
    1520        self.error_level = error_level or ErrorLevel.IMMEDIATE
    1521        self.error_message_context = error_message_context
    1522        self.max_errors = max_errors
    1523        self.dialect = Dialect.get_or_raise(dialect)
    1524        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.NESTED: 'NESTED'>, <TokenType.UNION: 'UNION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.STRUCT: 'STRUCT'>}
NESTED_TYPE_TOKENS = {<TokenType.LIST: 'LIST'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.MAP: 'MAP'>, <TokenType.NESTED: 'NESTED'>, <TokenType.RANGE: 'RANGE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.UNION: 'UNION'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NULLABLE: 'NULLABLE'>}
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.UBIGINT: 'UBIGINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UNION: 'UNION'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.UUID: 'UUID'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INET: 'INET'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BLOB: 'BLOB'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT: 'INT'>, <TokenType.DATE: 'DATE'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.POINT: 'POINT'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIME: 'TIME'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.DATE32: 'DATE32'>, <TokenType.MAP: 'MAP'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NAME: 'NAME'>, <TokenType.IPV6: 'IPV6'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.RING: 'RING'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOID: 'VOID'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.BIT: 'BIT'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.LIST: 'LIST'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.JSON: 'JSON'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.TINYINT: 'TINYINT'>}
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.DASH: 'DASH'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.DOT: 'DOT'>, <TokenType.HASH: 'HASH'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.SLASH: 'SLASH'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.EQ: 'EQ'>, <TokenType.AMP: 'AMP'>, <TokenType.TILDA: 'TILDA'>, <TokenType.SELECT: 'SELECT'>, <TokenType.CARET: 'CARET'>, <TokenType.LT: 'LT'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.NOT: 'NOT'>, <TokenType.PIPE: 'PIPE'>, <TokenType.GT: 'GT'>, <TokenType.MOD: 'MOD'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.COLON: 'COLON'>, <TokenType.STAR: 'STAR'>, <TokenType.COMMA: 'COMMA'>, <TokenType.PLUS: 'PLUS'>}
DB_CREATABLES = {<TokenType.STAGE: 'STAGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.TAG: 'TAG'>, <TokenType.MODEL: 'MODEL'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.SINK: 'SINK'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.TABLE: 'TABLE'>}
CREATABLES = {<TokenType.STAGE: 'STAGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.SINK: 'SINK'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.TAG: 'TAG'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>}
ALTERABLES = {<TokenType.INDEX: 'INDEX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.VIEW: 'VIEW'>}
ID_VAR_TOKENS = {<TokenType.TRUE: 'TRUE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.ASOF: 'ASOF'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.PUT: 'PUT'>, <TokenType.UUID: 'UUID'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.KILL: 'KILL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TAG: 'TAG'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.BLOB: 'BLOB'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.USE: 'USE'>, <TokenType.SINK: 'SINK'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.ROW: 'ROW'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NEXT: 'NEXT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.ALL: 'ALL'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.DESC: 'DESC'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ANY: 'ANY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TOP: 'TOP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT: 'INT'>, <TokenType.DATE: 'DATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.FULL: 'FULL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.KEEP: 'KEEP'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.POINT: 'POINT'>, <TokenType.GET: 'GET'>, <TokenType.IPV4: 'IPV4'>, <TokenType.RENAME: 'RENAME'>, <TokenType.TIME: 'TIME'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.CASE: 'CASE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.STAGE: 'STAGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.MAP: 'MAP'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.END: 'END'>, <TokenType.NAME: 'NAME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DETACH: 'DETACH'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.RING: 'RING'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.ASC: 'ASC'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SET: 'SET'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOID: 'VOID'>, <TokenType.IS: 'IS'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CUBE: 'CUBE'>, <TokenType.DIV: 'DIV'>, <TokenType.BIT: 'BIT'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.COPY: 'COPY'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.LIST: 'LIST'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.SOME: 'SOME'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.JSON: 'JSON'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.FINAL: 'FINAL'>, <TokenType.FILTER: 'FILTER'>}
TABLE_ALIAS_TOKENS = {<TokenType.TRUE: 'TRUE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.PUT: 'PUT'>, <TokenType.UUID: 'UUID'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.KILL: 'KILL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TAG: 'TAG'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.BLOB: 'BLOB'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.USE: 'USE'>, <TokenType.SINK: 'SINK'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.ROW: 'ROW'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NEXT: 'NEXT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.ALL: 'ALL'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.DESC: 'DESC'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ANY: 'ANY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TOP: 'TOP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT: 'INT'>, <TokenType.DATE: 'DATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.KEEP: 'KEEP'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.POINT: 'POINT'>, <TokenType.GET: 'GET'>, <TokenType.IPV4: 'IPV4'>, <TokenType.RENAME: 'RENAME'>, <TokenType.TIME: 'TIME'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.CASE: 'CASE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.STAGE: 'STAGE'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.MAP: 'MAP'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.END: 'END'>, <TokenType.NAME: 'NAME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DETACH: 'DETACH'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.RING: 'RING'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.ASC: 'ASC'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SET: 'SET'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOID: 'VOID'>, <TokenType.IS: 'IS'>, <TokenType.MERGE: 'MERGE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CUBE: 'CUBE'>, <TokenType.DIV: 'DIV'>, <TokenType.BIT: 'BIT'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.COPY: 'COPY'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.LIST: 'LIST'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.SOME: 'SOME'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.JSON: 'JSON'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.FINAL: 'FINAL'>, <TokenType.FILTER: 'FILTER'>}
ALIAS_TOKENS = {<TokenType.TRUE: 'TRUE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.ASOF: 'ASOF'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.PUT: 'PUT'>, <TokenType.UUID: 'UUID'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.KILL: 'KILL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TAG: 'TAG'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.BLOB: 'BLOB'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.USE: 'USE'>, <TokenType.SINK: 'SINK'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.ROW: 'ROW'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NEXT: 'NEXT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.ALL: 'ALL'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.DESC: 'DESC'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ANY: 'ANY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TOP: 'TOP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT: 'INT'>, <TokenType.DATE: 'DATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.FULL: 'FULL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.KEEP: 'KEEP'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.POINT: 'POINT'>, <TokenType.GET: 'GET'>, <TokenType.IPV4: 'IPV4'>, <TokenType.RENAME: 'RENAME'>, <TokenType.TIME: 'TIME'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.CASE: 'CASE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.STAGE: 'STAGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.MAP: 'MAP'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.END: 'END'>, <TokenType.NAME: 'NAME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DETACH: 'DETACH'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.RING: 'RING'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.ASC: 'ASC'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SET: 'SET'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOID: 'VOID'>, <TokenType.IS: 'IS'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CUBE: 'CUBE'>, <TokenType.DIV: 'DIV'>, <TokenType.BIT: 'BIT'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.COPY: 'COPY'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.LIST: 'LIST'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.SOME: 'SOME'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.JSON: 'JSON'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.FINAL: 'FINAL'>, <TokenType.FILTER: 'FILTER'>}
COLON_PLACEHOLDER_TOKENS = {<TokenType.TRUE: 'TRUE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.ASOF: 'ASOF'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.PUT: 'PUT'>, <TokenType.UUID: 'UUID'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.KILL: 'KILL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TAG: 'TAG'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.BLOB: 'BLOB'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.USE: 'USE'>, <TokenType.SINK: 'SINK'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.ROW: 'ROW'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NEXT: 'NEXT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.ALL: 'ALL'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.DESC: 'DESC'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ANY: 'ANY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TOP: 'TOP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT: 'INT'>, <TokenType.DATE: 'DATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.FULL: 'FULL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.KEEP: 'KEEP'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.POINT: 'POINT'>, <TokenType.GET: 'GET'>, <TokenType.IPV4: 'IPV4'>, <TokenType.RENAME: 'RENAME'>, <TokenType.TIME: 'TIME'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.CASE: 'CASE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.STAGE: 'STAGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.MAP: 'MAP'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.END: 'END'>, <TokenType.NAME: 'NAME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DETACH: 'DETACH'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.RING: 'RING'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.ASC: 'ASC'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SET: 'SET'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOID: 'VOID'>, <TokenType.IS: 'IS'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CUBE: 'CUBE'>, <TokenType.DIV: 'DIV'>, <TokenType.BIT: 'BIT'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.COPY: 'COPY'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.LIST: 'LIST'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.SOME: 'SOME'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.JSON: 'JSON'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.FINAL: 'FINAL'>, <TokenType.FILTER: 'FILTER'>}
ARRAY_CONSTRUCTORS = {'ARRAY': <class 'sqlglot.expressions.Array'>, 'LIST': <class 'sqlglot.expressions.List'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.TRUE: 'TRUE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.PUT: 'PUT'>, <TokenType.UUID: 'UUID'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.KILL: 'KILL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TAG: 'TAG'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.BLOB: 'BLOB'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.USE: 'USE'>, <TokenType.SINK: 'SINK'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.ROW: 'ROW'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NEXT: 'NEXT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.ALL: 'ALL'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.DESC: 'DESC'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ANY: 'ANY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TOP: 'TOP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT: 'INT'>, <TokenType.DATE: 'DATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.KEEP: 'KEEP'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.POINT: 'POINT'>, <TokenType.GET: 'GET'>, <TokenType.IPV4: 'IPV4'>, <TokenType.RENAME: 'RENAME'>, <TokenType.TIME: 'TIME'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.CASE: 'CASE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.STAGE: 'STAGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.MAP: 'MAP'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.END: 'END'>, <TokenType.NAME: 'NAME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DETACH: 'DETACH'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.RING: 'RING'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.ASC: 'ASC'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SET: 'SET'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOID: 'VOID'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CUBE: 'CUBE'>, <TokenType.DIV: 'DIV'>, <TokenType.BIT: 'BIT'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.COPY: 'COPY'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.LIST: 'LIST'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.SOME: 'SOME'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.JSON: 'JSON'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.FINAL: 'FINAL'>, <TokenType.FILTER: 'FILTER'>}
UPDATE_ALIAS_TOKENS = {<TokenType.TRUE: 'TRUE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.PUT: 'PUT'>, <TokenType.UUID: 'UUID'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.KILL: 'KILL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TAG: 'TAG'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.BLOB: 'BLOB'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.USE: 'USE'>, <TokenType.SINK: 'SINK'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.ROW: 'ROW'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NEXT: 'NEXT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.ALL: 'ALL'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.DESC: 'DESC'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ANY: 'ANY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TOP: 'TOP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT: 'INT'>, <TokenType.DATE: 'DATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.KEEP: 'KEEP'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.POINT: 'POINT'>, <TokenType.GET: 'GET'>, <TokenType.IPV4: 'IPV4'>, <TokenType.RENAME: 'RENAME'>, <TokenType.TIME: 'TIME'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.CASE: 'CASE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.STAGE: 'STAGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.MAP: 'MAP'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.END: 'END'>, <TokenType.NAME: 'NAME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DETACH: 'DETACH'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.RING: 'RING'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.ASC: 'ASC'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOID: 'VOID'>, <TokenType.IS: 'IS'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CUBE: 'CUBE'>, <TokenType.DIV: 'DIV'>, <TokenType.BIT: 'BIT'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.COPY: 'COPY'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.LIST: 'LIST'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.SOME: 'SOME'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.JSON: 'JSON'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.FINAL: 'FINAL'>, <TokenType.FILTER: 'FILTER'>}
TRIM_TYPES = {'TRAILING', 'BOTH', 'LEADING'}
FUNC_TOKENS = {<TokenType.UBIGINT: 'UBIGINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UNION: 'UNION'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.UUID: 'UUID'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.INET: 'INET'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BLOB: 'BLOB'>, <TokenType.LEFT: 'LEFT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.ROW: 'ROW'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NEXT: 'NEXT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.XOR: 'XOR'>, <TokenType.ALL: 'ALL'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ANY: 'ANY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.DATE: 'DATE'>, <TokenType.INT: 'INT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.POINT: 'POINT'>, <TokenType.GET: 'GET'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIME: 'TIME'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.DATE32: 'DATE32'>, <TokenType.MAP: 'MAP'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NAME: 'NAME'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.RING: 'RING'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOID: 'VOID'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.GLOB: 'GLOB'>, <TokenType.BIT: 'BIT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.RANGE: 'RANGE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.LIST: 'LIST'>, <TokenType.LIKE: 'LIKE'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.INSERT: 'INSERT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.JSON: 'JSON'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.SOME: 'SOME'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.NULL: 'NULL'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.FILTER: 'FILTER'>}
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.TIME: 'TIME'>, <TokenType.TIMETZ: 'TIMETZ'>}
TIMESTAMPS = {<TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>}
SET_OPERATIONS = {<TokenType.UNION: 'UNION'>, <TokenType.EXCEPT: 'EXCEPT'>, <TokenType.INTERSECT: 'INTERSECT'>}
JOIN_METHODS = {<TokenType.POSITIONAL: 'POSITIONAL'>, <TokenType.ASOF: 'ASOF'>, <TokenType.NATURAL: 'NATURAL'>}
JOIN_SIDES = {<TokenType.RIGHT: 'RIGHT'>, <TokenType.LEFT: 'LEFT'>, <TokenType.FULL: 'FULL'>}
JOIN_KINDS = {<TokenType.OUTER: 'OUTER'>, <TokenType.CROSS: 'CROSS'>, <TokenType.INNER: 'INNER'>, <TokenType.STRAIGHT_JOIN: 'STRAIGHT_JOIN'>, <TokenType.SEMI: 'SEMI'>, <TokenType.ANTI: 'ANTI'>}
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 = {'LIKE', 'CHECK', 'PERIOD', 'UNIQUE', 'BUCKET', 'FOREIGN KEY', 'TRUNCATE', 'EXCLUDE', 'PRIMARY KEY', 'WATERMARK'}
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.STRING: 'STRING'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>}
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 = {'ARG_MAX': <function Parser.<dictcomp>.<lambda>>, 'ARGMAX': <function Parser.<dictcomp>.<lambda>>, 'MAX_BY': <function Parser.<dictcomp>.<lambda>>, 'ARG_MIN': <function Parser.<dictcomp>.<lambda>>, 'ARGMIN': <function Parser.<dictcomp>.<lambda>>, 'MIN_BY': <function Parser.<dictcomp>.<lambda>>, '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.SELECT: 'SELECT'>, <TokenType.WITH: 'WITH'>, <TokenType.L_PAREN: 'L_PAREN'>}
PRE_VOLATILE_TOKENS = {<TokenType.REPLACE: 'REPLACE'>, <TokenType.CREATE: 'CREATE'>, <TokenType.UNIQUE: 'UNIQUE'>}
TRANSACTION_KIND = {'IMMEDIATE', 'DEFERRED', 'EXCLUSIVE'}
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 = {'REPLACE', 'FAIL', 'ROLLBACK', 'ABORT', 'IGNORE'}
CLONE_KEYWORDS = {'CLONE', 'COPY'}
HISTORICAL_DATA_PREFIX = {'BEFORE', 'AT', 'END'}
HISTORICAL_DATA_KIND = {'STATEMENT', 'OFFSET', 'TIMESTAMP', 'STREAM'}
OPCLASS_FOLLOW_KEYWORDS = {'NULLS', 'ASC', 'WITH', 'DESC'}
OPTYPE_FOLLOW_TOKENS = {<TokenType.R_PAREN: 'R_PAREN'>, <TokenType.COMMA: 'COMMA'>}
TABLE_INDEX_HINT_TOKENS = {<TokenType.USE: 'USE'>, <TokenType.IGNORE: 'IGNORE'>, <TokenType.FORCE: 'FORCE'>}
VIEW_ATTRIBUTES = {'SCHEMABINDING', 'VIEW_METADATA', 'ENCRYPTION'}
WINDOW_ALIAS_TOKENS = {<TokenType.TRUE: 'TRUE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.ASOF: 'ASOF'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.PUT: 'PUT'>, <TokenType.UUID: 'UUID'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.KILL: 'KILL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TAG: 'TAG'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.BLOB: 'BLOB'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.USE: 'USE'>, <TokenType.SINK: 'SINK'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.ROW: 'ROW'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NEXT: 'NEXT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.ALL: 'ALL'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.DESC: 'DESC'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ANY: 'ANY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TOP: 'TOP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT: 'INT'>, <TokenType.DATE: 'DATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.FULL: 'FULL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.KEEP: 'KEEP'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.POINT: 'POINT'>, <TokenType.GET: 'GET'>, <TokenType.IPV4: 'IPV4'>, <TokenType.RENAME: 'RENAME'>, <TokenType.TIME: 'TIME'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.CASE: 'CASE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.STAGE: 'STAGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.MAP: 'MAP'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.END: 'END'>, <TokenType.NAME: 'NAME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DETACH: 'DETACH'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.RING: 'RING'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.ASC: 'ASC'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SET: 'SET'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOID: 'VOID'>, <TokenType.IS: 'IS'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CUBE: 'CUBE'>, <TokenType.DIV: 'DIV'>, <TokenType.BIT: 'BIT'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.COPY: 'COPY'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.LIST: 'LIST'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.SOME: 'SOME'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.JSON: 'JSON'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.FINAL: 'FINAL'>, <TokenType.FILTER: 'FILTER'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'PRECEDING', 'FOLLOWING'}
JSON_KEY_VALUE_SEPARATOR_TOKENS = {<TokenType.IS: 'IS'>, <TokenType.COMMA: 'COMMA'>, <TokenType.COLON: 'COLON'>}
FETCH_TOKENS = {<TokenType.TRUE: 'TRUE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.ASOF: 'ASOF'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.PUT: 'PUT'>, <TokenType.UUID: 'UUID'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.KILL: 'KILL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TAG: 'TAG'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.BLOB: 'BLOB'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.USE: 'USE'>, <TokenType.SINK: 'SINK'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NEXT: 'NEXT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.ALL: 'ALL'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.DESC: 'DESC'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ANY: 'ANY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TOP: 'TOP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT: 'INT'>, <TokenType.DATE: 'DATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.FULL: 'FULL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.KEEP: 'KEEP'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.POINT: 'POINT'>, <TokenType.GET: 'GET'>, <TokenType.IPV4: 'IPV4'>, <TokenType.RENAME: 'RENAME'>, <TokenType.TIME: 'TIME'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.CASE: 'CASE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.STAGE: 'STAGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.MAP: 'MAP'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.END: 'END'>, <TokenType.NAME: 'NAME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.APPLY: 'APPLY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DETACH: 'DETACH'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.RING: 'RING'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.ASC: 'ASC'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SET: 'SET'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOID: 'VOID'>, <TokenType.IS: 'IS'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.MERGE: 'MERGE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CUBE: 'CUBE'>, <TokenType.DIV: 'DIV'>, <TokenType.BIT: 'BIT'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.COPY: 'COPY'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.LIST: 'LIST'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.SOME: 'SOME'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.JSON: 'JSON'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.FINAL: 'FINAL'>, <TokenType.FILTER: 'FILTER'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.KEY: 'KEY'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.TRUE: 'TRUE'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.XML: 'XML'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.PUT: 'PUT'>, <TokenType.UUID: 'UUID'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.KILL: 'KILL'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.INET: 'INET'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TAG: 'TAG'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.BLOB: 'BLOB'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.USE: 'USE'>, <TokenType.SINK: 'SINK'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.ROW: 'ROW'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NEXT: 'NEXT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.ALL: 'ALL'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.DESC: 'DESC'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ANY: 'ANY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.TOP: 'TOP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.INT: 'INT'>, <TokenType.DATE: 'DATE'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.DELETE: 'DELETE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.KEEP: 'KEEP'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.POINT: 'POINT'>, <TokenType.GET: 'GET'>, <TokenType.IPV4: 'IPV4'>, <TokenType.RENAME: 'RENAME'>, <TokenType.TIME: 'TIME'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.CASE: 'CASE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.STAGE: 'STAGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.MAP: 'MAP'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.END: 'END'>, <TokenType.NAME: 'NAME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.DETACH: 'DETACH'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.RING: 'RING'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.ASC: 'ASC'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.UINT: 'UINT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SET: 'SET'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VAR: 'VAR'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOID: 'VOID'>, <TokenType.IS: 'IS'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.CUBE: 'CUBE'>, <TokenType.DIV: 'DIV'>, <TokenType.BIT: 'BIT'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.COPY: 'COPY'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.LIST: 'LIST'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.INT128: 'INT128'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.FALSE: 'FALSE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.SOME: 'SOME'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.JSON: 'JSON'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.NULL: 'NULL'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.FINAL: 'FINAL'>, <TokenType.FILTER: 'FILTER'>}
SELECT_START_TOKENS = {<TokenType.SELECT: 'SELECT'>, <TokenType.WITH: 'WITH'>, <TokenType.L_PAREN: 'L_PAREN'>}
COPY_INTO_VARLEN_OPTIONS = {'FORMAT_OPTIONS', 'FILE_FORMAT', 'CREDENTIAL', 'COPY_OPTIONS'}
IS_JSON_PREDICATE_KIND = {'OBJECT', 'VALUE', 'ARRAY', 'SCALAR'}
ODBC_DATETIME_LITERALS = {'d': <class 'sqlglot.expressions.Date'>, 't': <class 'sqlglot.expressions.Time'>, 'ts': <class 'sqlglot.expressions.Timestamp'>}
ON_CONDITION_TOKENS = {'FALSE', 'NULL', 'EMPTY', 'TRUE', 'ERROR'}
PRIVILEGE_FOLLOW_TOKENS = {<TokenType.L_PAREN: 'L_PAREN'>, <TokenType.ON: 'ON'>, <TokenType.COMMA: 'COMMA'>}
DESCRIBE_STYLES = {'ANALYZE', 'HISTORY', 'EXTENDED', 'FORMATTED'}
ANALYZE_STYLES = {'SAMPLE', 'SKIP_LOCKED', 'VERBOSE', 'NO_WRITE_TO_BINLOG', 'LOCAL', 'FULL', 'BUFFER_USAGE_LIMIT'}
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 = {'SUBPARTITION', 'PARTITION'}
AMBIGUOUS_ALIAS_TOKENS = (<TokenType.LIMIT: 'LIMIT'>, <TokenType.OFFSET: 'OFFSET'>)
OPERATION_MODIFIERS: Set[str] = set()
RECURSIVE_CTE_SEARCH_KIND = {'BREADTH', 'CYCLE', 'DEPTH'}
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 = {'offset', 'order', 'limit'}
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

    1526    def reset(self):
    1527        self.sql = ""
    1528        self.errors = []
    1529        self._tokens = []
    1530        self._index = 0
    1531        self._curr = None
    1532        self._next = None
    1533        self._prev = None
    1534        self._prev_comments = None

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

    1536    def parse(
    1537        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    1538    ) -> t.List[t.Optional[exp.Expression]]:
    1539        """
    1540        Parses a list of tokens and returns a list of syntax trees, one tree
    1541        per parsed SQL statement.
    1542
    1543        Args:
    1544            raw_tokens: The list of tokens.
    1545            sql: The original SQL string, used to produce helpful debug messages.
    1546
    1547        Returns:
    1548            The list of the produced syntax trees.
    1549        """
    1550        return self._parse(
    1551            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    1552        )

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

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

    1628    def check_errors(self) -> None:
    1629        """Logs or raises any found errors, depending on the chosen error level setting."""
    1630        if self.error_level == ErrorLevel.WARN:
    1631            for error in self.errors:
    1632                logger.error(str(error))
    1633        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1634            raise ParseError(
    1635                concat_messages(self.errors, self.max_errors),
    1636                errors=merge_errors(self.errors),
    1637            )

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

    1639    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1640        """
    1641        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1642        error level setting.
    1643        """
    1644        token = token or self._curr or self._prev or Token.string("")
    1645        start = token.start
    1646        end = token.end + 1
    1647        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1648        highlight = self.sql[start:end]
    1649        end_context = self.sql[end : end + self.error_message_context]
    1650
    1651        error = ParseError.new(
    1652            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1653            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1654            description=message,
    1655            line=token.line,
    1656            col=token.col,
    1657            start_context=start_context,
    1658            highlight=highlight,
    1659            end_context=end_context,
    1660        )
    1661
    1662        if self.error_level == ErrorLevel.IMMEDIATE:
    1663            raise error
    1664
    1665        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

    1667    def expression(
    1668        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1669    ) -> E:
    1670        """
    1671        Creates a new, validated Expression.
    1672
    1673        Args:
    1674            exp_class: The expression class to instantiate.
    1675            comments: An optional list of comments to attach to the expression.
    1676            kwargs: The arguments to set for the expression along with their respective values.
    1677
    1678        Returns:
    1679            The target expression.
    1680        """
    1681        instance = exp_class(**kwargs)
    1682        instance.add_comments(comments) if comments else self._add_comments(instance)
    1683        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

    1690    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1691        """
    1692        Validates an Expression, making sure that all its mandatory arguments are set.
    1693
    1694        Args:
    1695            expression: The expression to validate.
    1696            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1697
    1698        Returns:
    1699            The validated expression.
    1700        """
    1701        if self.error_level != ErrorLevel.IGNORE:
    1702            for error_message in expression.error_messages(args):
    1703                self.raise_error(error_message)
    1704
    1705        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

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

errors
sql