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

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

    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()

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

    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

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

    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        )

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

    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]

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

    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            )

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

    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)

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

    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)

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

    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

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

    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        )

errors
sql