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

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, is_null: Optional[bool] = None) -> sqlglot.expressions.Coalesce: View Source

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

def build_locate_strposition(args: List): View Source

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

class Parser: View Source

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

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

    1534    def __init__(
    1535        self,
    1536        error_level: t.Optional[ErrorLevel] = None,
    1537        error_message_context: int = 100,
    1538        max_errors: int = 3,
    1539        dialect: DialectType = None,
    1540    ):
    1541        from sqlglot.dialects import Dialect
    1542
    1543        self.error_level = error_level or ErrorLevel.IMMEDIATE
    1544        self.error_message_context = error_message_context
    1545        self.max_errors = max_errors
    1546        self.dialect = Dialect.get_or_raise(dialect)
    1547        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_CONCAT_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConcatAgg'>>, '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_INTERSECT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayIntersect'>>, 'ARRAY_INTERSECTION': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayIntersect'>>, 'ARRAY_OVERLAPS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayOverlaps'>>, 'ARRAY_REMOVE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayRemove'>>, '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>, 'CONVERT_TO_CHARSET': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ConvertToCharset'>>, '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'>>, 'ENDS_WITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.EndsWith'>>, 'ENDSWITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.EndsWith'>>, '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'>>, 'ST_DISTANCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StDistance'>>, 'ST_POINT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StPoint'>>, 'ST_MAKEPOINT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StPoint'>>, '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'>>, 'STRTOK_TO_ARRAY': <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.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.OBJECT: 'OBJECT'>}
NESTED_TYPE_TOKENS = {<TokenType.OBJECT: 'OBJECT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.RANGE: 'RANGE'>, <TokenType.LIST: 'LIST'>, <TokenType.NESTED: 'NESTED'>, <TokenType.UNION: 'UNION'>, <TokenType.MAP: 'MAP'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ARRAY: 'ARRAY'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM: 'ENUM'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DYNAMIC: 'DYNAMIC'>}
AGGREGATE_TYPE_TOKENS = {<TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>}
TYPE_TOKENS = {<TokenType.VARCHAR: 'VARCHAR'>, <TokenType.CHAR: 'CHAR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.MAP: 'MAP'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.XML: 'XML'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIME: 'TIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.JSON: 'JSON'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT128: 'INT128'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UINT: 'UINT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BIT: 'BIT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BLOB: 'BLOB'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.RING: 'RING'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UINT256: 'UINT256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.LIST: 'LIST'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INET: 'INET'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.VOID: 'VOID'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NAME: 'NAME'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.INT: 'INT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.INT256: 'INT256'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DATE: 'DATE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.UNION: 'UNION'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.IPV6: 'IPV6'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>}
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.SELECT: 'SELECT'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.MOD: 'MOD'>, <TokenType.COMMA: 'COMMA'>, <TokenType.COLON: 'COLON'>, <TokenType.SLASH: 'SLASH'>, <TokenType.TILDA: 'TILDA'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.NOT: 'NOT'>, <TokenType.DOT: 'DOT'>, <TokenType.DASH: 'DASH'>, <TokenType.CARET: 'CARET'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.STAR: 'STAR'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.HASH: 'HASH'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.PIPE: 'PIPE'>, <TokenType.PLUS: 'PLUS'>, <TokenType.EQ: 'EQ'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.GT: 'GT'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.AMP: 'AMP'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.LT: 'LT'>, <TokenType.PARAMETER: 'PARAMETER'>}
DB_CREATABLES = {<TokenType.STAGE: 'STAGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SINK: 'SINK'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TAG: 'TAG'>, <TokenType.MODEL: 'MODEL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SCHEMA: 'SCHEMA'>}
CREATABLES = {<TokenType.FUNCTION: 'FUNCTION'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SINK: 'SINK'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TAG: 'TAG'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TABLE: 'TABLE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.STAGE: 'STAGE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.SEQUENCE: 'SEQUENCE'>}
ALTERABLES = {<TokenType.VIEW: 'VIEW'>, <TokenType.TABLE: 'TABLE'>, <TokenType.INDEX: 'INDEX'>}
ID_VAR_TOKENS = {<TokenType.SHOW: 'SHOW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SINK: 'SINK'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.CHAR: 'CHAR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.MAP: 'MAP'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.APPLY: 'APPLY'>, <TokenType.RENAME: 'RENAME'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UINT128: 'UINT128'>, <TokenType.STAGE: 'STAGE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DIV: 'DIV'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.USE: 'USE'>, <TokenType.XML: 'XML'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.PUT: 'PUT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIME: 'TIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.IS: 'IS'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.JSON: 'JSON'>, <TokenType.VAR: 'VAR'>, <TokenType.CUBE: 'CUBE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.INT128: 'INT128'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.UINT: 'UINT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BIT: 'BIT'>, <TokenType.COPY: 'COPY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BLOB: 'BLOB'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CASE: 'CASE'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANY: 'ANY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NEXT: 'NEXT'>, <TokenType.ROW: 'ROW'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.ASC: 'ASC'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.BINARY: 'BINARY'>, <TokenType.RING: 'RING'>, <TokenType.TAG: 'TAG'>, <TokenType.RANGE: 'RANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.GET: 'GET'>, <TokenType.POINT: 'POINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.TOP: 'TOP'>, <TokenType.UINT256: 'UINT256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.ROWS: 'ROWS'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FIRST: 'FIRST'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TRUE: 'TRUE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ALL: 'ALL'>, <TokenType.KILL: 'KILL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.FULL: 'FULL'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.SET: 'SET'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.LIST: 'LIST'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ASOF: 'ASOF'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INET: 'INET'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.VOID: 'VOID'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NAME: 'NAME'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.INT: 'INT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DETACH: 'DETACH'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.INT256: 'INT256'>, <TokenType.DELETE: 'DELETE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DATE: 'DATE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DESC: 'DESC'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>}
TABLE_ALIAS_TOKENS = {<TokenType.SHOW: 'SHOW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SINK: 'SINK'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.CHAR: 'CHAR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.MAP: 'MAP'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.RENAME: 'RENAME'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UINT128: 'UINT128'>, <TokenType.STAGE: 'STAGE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DIV: 'DIV'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.USE: 'USE'>, <TokenType.XML: 'XML'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.PUT: 'PUT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIME: 'TIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.IS: 'IS'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.JSON: 'JSON'>, <TokenType.VAR: 'VAR'>, <TokenType.CUBE: 'CUBE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.INT128: 'INT128'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.UINT: 'UINT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BIT: 'BIT'>, <TokenType.COPY: 'COPY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BLOB: 'BLOB'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CASE: 'CASE'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANY: 'ANY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NEXT: 'NEXT'>, <TokenType.ROW: 'ROW'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.MERGE: 'MERGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.ASC: 'ASC'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.RING: 'RING'>, <TokenType.TAG: 'TAG'>, <TokenType.RANGE: 'RANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.GET: 'GET'>, <TokenType.POINT: 'POINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.TOP: 'TOP'>, <TokenType.UINT256: 'UINT256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.ROWS: 'ROWS'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FIRST: 'FIRST'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TRUE: 'TRUE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ALL: 'ALL'>, <TokenType.KILL: 'KILL'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.SET: 'SET'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.LIST: 'LIST'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INET: 'INET'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.VOID: 'VOID'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NAME: 'NAME'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.INT: 'INT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DETACH: 'DETACH'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.INT256: 'INT256'>, <TokenType.DELETE: 'DELETE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DATE: 'DATE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DESC: 'DESC'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>}
ALIAS_TOKENS = {<TokenType.SHOW: 'SHOW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SINK: 'SINK'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.CHAR: 'CHAR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.MAP: 'MAP'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.APPLY: 'APPLY'>, <TokenType.RENAME: 'RENAME'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UINT128: 'UINT128'>, <TokenType.STAGE: 'STAGE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DIV: 'DIV'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.USE: 'USE'>, <TokenType.XML: 'XML'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.PUT: 'PUT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIME: 'TIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.IS: 'IS'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.JSON: 'JSON'>, <TokenType.VAR: 'VAR'>, <TokenType.CUBE: 'CUBE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.INT128: 'INT128'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.UINT: 'UINT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BIT: 'BIT'>, <TokenType.COPY: 'COPY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BLOB: 'BLOB'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CASE: 'CASE'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANY: 'ANY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NEXT: 'NEXT'>, <TokenType.ROW: 'ROW'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.ASC: 'ASC'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.BINARY: 'BINARY'>, <TokenType.RING: 'RING'>, <TokenType.TAG: 'TAG'>, <TokenType.RANGE: 'RANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.GET: 'GET'>, <TokenType.POINT: 'POINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.TOP: 'TOP'>, <TokenType.UINT256: 'UINT256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.ROWS: 'ROWS'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FIRST: 'FIRST'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TRUE: 'TRUE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ALL: 'ALL'>, <TokenType.KILL: 'KILL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.FULL: 'FULL'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.SET: 'SET'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.LIST: 'LIST'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ASOF: 'ASOF'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INET: 'INET'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.VOID: 'VOID'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NAME: 'NAME'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.INT: 'INT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DETACH: 'DETACH'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.INT256: 'INT256'>, <TokenType.DELETE: 'DELETE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DATE: 'DATE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DESC: 'DESC'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>}
COLON_PLACEHOLDER_TOKENS = {<TokenType.SHOW: 'SHOW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SINK: 'SINK'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.CHAR: 'CHAR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.MAP: 'MAP'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.APPLY: 'APPLY'>, <TokenType.RENAME: 'RENAME'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UINT128: 'UINT128'>, <TokenType.STAGE: 'STAGE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DIV: 'DIV'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.USE: 'USE'>, <TokenType.XML: 'XML'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.PUT: 'PUT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIME: 'TIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.IS: 'IS'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.JSON: 'JSON'>, <TokenType.VAR: 'VAR'>, <TokenType.CUBE: 'CUBE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.INT128: 'INT128'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.UINT: 'UINT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BIT: 'BIT'>, <TokenType.COPY: 'COPY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BLOB: 'BLOB'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CASE: 'CASE'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANY: 'ANY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NEXT: 'NEXT'>, <TokenType.ROW: 'ROW'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.ASC: 'ASC'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.BINARY: 'BINARY'>, <TokenType.RING: 'RING'>, <TokenType.TAG: 'TAG'>, <TokenType.RANGE: 'RANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.GET: 'GET'>, <TokenType.POINT: 'POINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.TOP: 'TOP'>, <TokenType.UINT256: 'UINT256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.ROWS: 'ROWS'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FIRST: 'FIRST'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TRUE: 'TRUE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ALL: 'ALL'>, <TokenType.KILL: 'KILL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.FULL: 'FULL'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.SET: 'SET'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.LIST: 'LIST'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ASOF: 'ASOF'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INET: 'INET'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.VOID: 'VOID'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NAME: 'NAME'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.INT: 'INT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DETACH: 'DETACH'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.INT256: 'INT256'>, <TokenType.DELETE: 'DELETE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DATE: 'DATE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DESC: 'DESC'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>}
ARRAY_CONSTRUCTORS = {'ARRAY': <class 'sqlglot.expressions.Array'>, 'LIST': <class 'sqlglot.expressions.List'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.SHOW: 'SHOW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SINK: 'SINK'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.CHAR: 'CHAR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.MAP: 'MAP'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.RENAME: 'RENAME'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UINT128: 'UINT128'>, <TokenType.STAGE: 'STAGE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DIV: 'DIV'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.USE: 'USE'>, <TokenType.XML: 'XML'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.PUT: 'PUT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIME: 'TIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.JSON: 'JSON'>, <TokenType.VAR: 'VAR'>, <TokenType.CUBE: 'CUBE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.INT128: 'INT128'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.UINT: 'UINT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BIT: 'BIT'>, <TokenType.COPY: 'COPY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BLOB: 'BLOB'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CASE: 'CASE'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANY: 'ANY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NEXT: 'NEXT'>, <TokenType.ROW: 'ROW'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MERGE: 'MERGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.ASC: 'ASC'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.RING: 'RING'>, <TokenType.TAG: 'TAG'>, <TokenType.RANGE: 'RANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.GET: 'GET'>, <TokenType.POINT: 'POINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.TOP: 'TOP'>, <TokenType.UINT256: 'UINT256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.ROWS: 'ROWS'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FIRST: 'FIRST'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TRUE: 'TRUE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ALL: 'ALL'>, <TokenType.KILL: 'KILL'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.SET: 'SET'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.LIST: 'LIST'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INET: 'INET'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.VOID: 'VOID'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NAME: 'NAME'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.INT: 'INT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DETACH: 'DETACH'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.INT256: 'INT256'>, <TokenType.DELETE: 'DELETE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DATE: 'DATE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DESC: 'DESC'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>}
UPDATE_ALIAS_TOKENS = {<TokenType.SHOW: 'SHOW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SINK: 'SINK'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.CHAR: 'CHAR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.MAP: 'MAP'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.RENAME: 'RENAME'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UINT128: 'UINT128'>, <TokenType.STAGE: 'STAGE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DIV: 'DIV'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.USE: 'USE'>, <TokenType.XML: 'XML'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.PUT: 'PUT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIME: 'TIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.IS: 'IS'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.JSON: 'JSON'>, <TokenType.VAR: 'VAR'>, <TokenType.CUBE: 'CUBE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.INT128: 'INT128'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.UINT: 'UINT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BIT: 'BIT'>, <TokenType.COPY: 'COPY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BLOB: 'BLOB'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CASE: 'CASE'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANY: 'ANY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NEXT: 'NEXT'>, <TokenType.ROW: 'ROW'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MERGE: 'MERGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.ASC: 'ASC'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.RING: 'RING'>, <TokenType.TAG: 'TAG'>, <TokenType.RANGE: 'RANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.GET: 'GET'>, <TokenType.POINT: 'POINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.TOP: 'TOP'>, <TokenType.UINT256: 'UINT256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.ROWS: 'ROWS'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FIRST: 'FIRST'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TRUE: 'TRUE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ALL: 'ALL'>, <TokenType.KILL: 'KILL'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.LIST: 'LIST'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INET: 'INET'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.VOID: 'VOID'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NAME: 'NAME'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.INT: 'INT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DETACH: 'DETACH'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.INT256: 'INT256'>, <TokenType.DELETE: 'DELETE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DATE: 'DATE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DESC: 'DESC'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>}
TRIM_TYPES = {'BOTH', 'LEADING', 'TRAILING'}
FUNC_TOKENS = {<TokenType.ILIKE: 'ILIKE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.CHAR: 'CHAR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.MAP: 'MAP'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.LIKE: 'LIKE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.XML: 'XML'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIME: 'TIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.JSON: 'JSON'>, <TokenType.VAR: 'VAR'>, <TokenType.INSERT: 'INSERT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.FILTER: 'FILTER'>, <TokenType.INT128: 'INT128'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.UINT: 'UINT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BIT: 'BIT'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BLOB: 'BLOB'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANY: 'ANY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NEXT: 'NEXT'>, <TokenType.ROW: 'ROW'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.XOR: 'XOR'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.RING: 'RING'>, <TokenType.RANGE: 'RANGE'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.GET: 'GET'>, <TokenType.POINT: 'POINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UINT256: 'UINT256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FIRST: 'FIRST'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ALL: 'ALL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.LIST: 'LIST'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INET: 'INET'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.VOID: 'VOID'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NAME: 'NAME'>, <TokenType.GLOB: 'GLOB'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.INT: 'INT'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.INT256: 'INT256'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.JSONB: 'JSONB'>, <TokenType.DATE: 'DATE'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.UNION: 'UNION'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.IPV6: 'IPV6'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>}
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.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIME: 'TIME'>}
SET_OPERATIONS = {<TokenType.EXCEPT: 'EXCEPT'>, <TokenType.UNION: 'UNION'>, <TokenType.INTERSECT: 'INTERSECT'>}
JOIN_METHODS = {<TokenType.POSITIONAL: 'POSITIONAL'>, <TokenType.ASOF: 'ASOF'>, <TokenType.NATURAL: 'NATURAL'>}
JOIN_SIDES = {<TokenType.LEFT: 'LEFT'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.FULL: 'FULL'>}
JOIN_KINDS = {<TokenType.SEMI: 'SEMI'>, <TokenType.CROSS: 'CROSS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.OUTER: 'OUTER'>, <TokenType.INNER: 'INNER'>, <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>>}
PIPE_SYNTAX_TRANSFORM_PARSERS = {'SELECT': <function Parser.<lambda>>, 'WHERE': <function Parser.<lambda>>, 'ORDER BY': <function Parser.<lambda>>, 'LIMIT': <function Parser.<lambda>>, 'OFFSET': <function Parser.<lambda>>, 'AGGREGATE': <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>>, 'ENVIRONMENT': <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 = {'EXCLUDE', 'BUCKET', 'LIKE', 'PERIOD', 'PRIMARY KEY', 'FOREIGN KEY', 'TRUNCATE', 'UNIQUE', 'CHECK', 'WATERMARK'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.STRING: 'STRING'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
KEY_VALUE_DEFINITIONS = (<class 'sqlglot.expressions.Alias'>, <class 'sqlglot.expressions.EQ'>, <class 'sqlglot.expressions.PropertyEQ'>, <class 'sqlglot.expressions.Slice'>)
FUNCTION_PARSERS = {'ARG_MAX': <function Parser.<dictcomp>.<lambda>>, 'ARGMAX': <function Parser.<dictcomp>.<lambda>>, 'MAX_BY': <function Parser.<dictcomp>.<lambda>>, 'ARG_MIN': <function Parser.<dictcomp>.<lambda>>, 'ARGMIN': <function Parser.<dictcomp>.<lambda>>, 'MIN_BY': <function Parser.<dictcomp>.<lambda>>, 'CAST': <function Parser.<lambda>>, 'CEIL': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'FLOOR': <function Parser.<lambda>>, 'GAP_FILL': <function Parser.<lambda>>, 'JSON_OBJECT': <function Parser.<lambda>>, 'JSON_OBJECTAGG': <function Parser.<lambda>>, 'JSON_TABLE': <function Parser.<lambda>>, 'MATCH': <function Parser.<lambda>>, 'NORMALIZE': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'OVERLAY': <function Parser.<lambda>>, 'POSITION': <function Parser.<lambda>>, 'PREDICT': <function Parser.<lambda>>, 'SAFE_CAST': <function Parser.<lambda>>, 'STRING_AGG': <function Parser.<lambda>>, 'SUBSTRING': <function Parser.<lambda>>, 'TRIM': <function Parser.<lambda>>, 'TRY_CAST': <function Parser.<lambda>>, 'TRY_CONVERT': <function Parser.<lambda>>, 'XMLELEMENT': <function Parser.<lambda>>, 'XMLTABLE': <function Parser.<lambda>>}
QUERY_MODIFIER_PARSERS = {<TokenType.MATCH_RECOGNIZE: 'MATCH_RECOGNIZE'>: <function Parser.<lambda>>, <TokenType.PREWHERE: 'PREWHERE'>: <function Parser.<lambda>>, <TokenType.WHERE: 'WHERE'>: <function Parser.<lambda>>, <TokenType.GROUP_BY: 'GROUP_BY'>: <function Parser.<lambda>>, <TokenType.HAVING: 'HAVING'>: <function Parser.<lambda>>, <TokenType.QUALIFY: 'QUALIFY'>: <function Parser.<lambda>>, <TokenType.WINDOW: 'WINDOW'>: <function Parser.<lambda>>, <TokenType.ORDER_BY: 'ORDER_BY'>: <function Parser.<lambda>>, <TokenType.LIMIT: 'LIMIT'>: <function Parser.<lambda>>, <TokenType.FETCH: 'FETCH'>: <function Parser.<lambda>>, <TokenType.OFFSET: 'OFFSET'>: <function Parser.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>, <TokenType.LOCK: 'LOCK'>: <function Parser.<lambda>>, <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>: <function Parser.<lambda>>, <TokenType.USING: 'USING'>: <function Parser.<lambda>>, <TokenType.CLUSTER_BY: 'CLUSTER_BY'>: <function Parser.<lambda>>, <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>: <function Parser.<lambda>>, <TokenType.SORT_BY: 'SORT_BY'>: <function Parser.<lambda>>, <TokenType.CONNECT_BY: 'CONNECT_BY'>: <function Parser.<lambda>>, <TokenType.START_WITH: 'START_WITH'>: <function Parser.<lambda>>}
SET_PARSERS = {'GLOBAL': <function Parser.<lambda>>, 'LOCAL': <function Parser.<lambda>>, 'SESSION': <function Parser.<lambda>>, 'TRANSACTION': <function Parser.<lambda>>}
SHOW_PARSERS: Dict[str, Callable] = {}
TYPE_LITERAL_PARSERS = {<Type.JSON: 'JSON'>: <function Parser.<lambda>>}
TYPE_CONVERTERS: Dict[sqlglot.expressions.DataType.Type, Callable[[sqlglot.expressions.DataType], sqlglot.expressions.DataType]] = {}
DDL_SELECT_TOKENS = {<TokenType.SELECT: 'SELECT'>, <TokenType.WITH: 'WITH'>, <TokenType.L_PAREN: 'L_PAREN'>}
PRE_VOLATILE_TOKENS = {<TokenType.CREATE: 'CREATE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.UNIQUE: 'UNIQUE'>}
TRANSACTION_KIND = {'IMMEDIATE', 'EXCLUSIVE', 'DEFERRED'}
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': ()}
WINDOW_EXCLUDE_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'NO': ('OTHERS',), 'CURRENT': ('ROW',), 'GROUP': (), 'TIES': ()}
INSERT_ALTERNATIVES = {'ABORT', 'FAIL', 'REPLACE', 'IGNORE', 'ROLLBACK'}
CLONE_KEYWORDS = {'CLONE', 'COPY'}
HISTORICAL_DATA_PREFIX = {'END', 'AT', 'BEFORE'}
HISTORICAL_DATA_KIND = {'TIMESTAMP', 'STATEMENT', 'VERSION', 'STREAM', 'OFFSET'}
OPCLASS_FOLLOW_KEYWORDS = {'ASC', 'WITH', 'DESC', 'NULLS'}
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', 'VIEW_METADATA', 'ENCRYPTION'}
WINDOW_ALIAS_TOKENS = {<TokenType.SHOW: 'SHOW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SINK: 'SINK'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.CHAR: 'CHAR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.MAP: 'MAP'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.APPLY: 'APPLY'>, <TokenType.RENAME: 'RENAME'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UINT128: 'UINT128'>, <TokenType.STAGE: 'STAGE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DIV: 'DIV'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.USE: 'USE'>, <TokenType.XML: 'XML'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.PUT: 'PUT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIME: 'TIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.IS: 'IS'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.JSON: 'JSON'>, <TokenType.VAR: 'VAR'>, <TokenType.CUBE: 'CUBE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.INT128: 'INT128'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.UINT: 'UINT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BIT: 'BIT'>, <TokenType.COPY: 'COPY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BLOB: 'BLOB'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CASE: 'CASE'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANY: 'ANY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NEXT: 'NEXT'>, <TokenType.ROW: 'ROW'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.ASC: 'ASC'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.BINARY: 'BINARY'>, <TokenType.RING: 'RING'>, <TokenType.TAG: 'TAG'>, <TokenType.RANGE: 'RANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.GET: 'GET'>, <TokenType.POINT: 'POINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.TOP: 'TOP'>, <TokenType.UINT256: 'UINT256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FIRST: 'FIRST'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TRUE: 'TRUE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ALL: 'ALL'>, <TokenType.KILL: 'KILL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.FULL: 'FULL'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.SET: 'SET'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.LIST: 'LIST'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ASOF: 'ASOF'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INET: 'INET'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.VOID: 'VOID'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NAME: 'NAME'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.INT: 'INT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DETACH: 'DETACH'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.INT256: 'INT256'>, <TokenType.DELETE: 'DELETE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DATE: 'DATE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DESC: 'DESC'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'PRECEDING', 'FOLLOWING'}
JSON_KEY_VALUE_SEPARATOR_TOKENS = {<TokenType.COMMA: 'COMMA'>, <TokenType.COLON: 'COLON'>, <TokenType.IS: 'IS'>}
FETCH_TOKENS = {<TokenType.SHOW: 'SHOW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SINK: 'SINK'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.CHAR: 'CHAR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.MAP: 'MAP'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.APPLY: 'APPLY'>, <TokenType.RENAME: 'RENAME'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UINT128: 'UINT128'>, <TokenType.STAGE: 'STAGE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DIV: 'DIV'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.USE: 'USE'>, <TokenType.XML: 'XML'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.PUT: 'PUT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIME: 'TIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.IS: 'IS'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.JSON: 'JSON'>, <TokenType.VAR: 'VAR'>, <TokenType.CUBE: 'CUBE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.INT128: 'INT128'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.UINT: 'UINT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BIT: 'BIT'>, <TokenType.COPY: 'COPY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BLOB: 'BLOB'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CASE: 'CASE'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANY: 'ANY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NEXT: 'NEXT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.ASC: 'ASC'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.SEMI: 'SEMI'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.BINARY: 'BINARY'>, <TokenType.RING: 'RING'>, <TokenType.TAG: 'TAG'>, <TokenType.RANGE: 'RANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.GET: 'GET'>, <TokenType.POINT: 'POINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.TOP: 'TOP'>, <TokenType.UINT256: 'UINT256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FIRST: 'FIRST'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TRUE: 'TRUE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ALL: 'ALL'>, <TokenType.KILL: 'KILL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.FULL: 'FULL'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.SET: 'SET'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.LIST: 'LIST'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ASOF: 'ASOF'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INET: 'INET'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.VOID: 'VOID'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NAME: 'NAME'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.INT: 'INT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DETACH: 'DETACH'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.INT256: 'INT256'>, <TokenType.DELETE: 'DELETE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DATE: 'DATE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DESC: 'DESC'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.KEY: 'KEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.SHOW: 'SHOW'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.SINK: 'SINK'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.CHAR: 'CHAR'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.MAP: 'MAP'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.RENAME: 'RENAME'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.UINT128: 'UINT128'>, <TokenType.STAGE: 'STAGE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.DIV: 'DIV'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.USE: 'USE'>, <TokenType.XML: 'XML'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.PUT: 'PUT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TIME: 'TIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.IS: 'IS'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.JSON: 'JSON'>, <TokenType.VAR: 'VAR'>, <TokenType.CUBE: 'CUBE'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.FILTER: 'FILTER'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.INT128: 'INT128'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.UINT: 'UINT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.BIT: 'BIT'>, <TokenType.COPY: 'COPY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BLOB: 'BLOB'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CASE: 'CASE'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.ANY: 'ANY'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.END: 'END'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.NESTED: 'NESTED'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.NEXT: 'NEXT'>, <TokenType.ROW: 'ROW'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATE32: 'DATE32'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MERGE: 'MERGE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.ASC: 'ASC'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.RING: 'RING'>, <TokenType.TAG: 'TAG'>, <TokenType.RANGE: 'RANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.TEXT: 'TEXT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.GET: 'GET'>, <TokenType.POINT: 'POINT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.TOP: 'TOP'>, <TokenType.UINT256: 'UINT256'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.LOAD: 'LOAD'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.ROWS: 'ROWS'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FIRST: 'FIRST'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.TRUE: 'TRUE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ALL: 'ALL'>, <TokenType.KILL: 'KILL'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.NULL: 'NULL'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.SET: 'SET'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.LIST: 'LIST'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.INET: 'INET'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.VOID: 'VOID'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NAME: 'NAME'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.INT: 'INT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DETACH: 'DETACH'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.INT256: 'INT256'>, <TokenType.DELETE: 'DELETE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.JSONB: 'JSONB'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DATE: 'DATE'>, <TokenType.IPV4: 'IPV4'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.KEEP: 'KEEP'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DESC: 'DESC'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>}
SELECT_START_TOKENS = {<TokenType.WITH: 'WITH'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.SELECT: 'SELECT'>}
COPY_INTO_VARLEN_OPTIONS = {'FILE_FORMAT', 'COPY_OPTIONS', 'FORMAT_OPTIONS', 'CREDENTIAL'}
IS_JSON_PREDICATE_KIND = {'VALUE', 'OBJECT', 'ARRAY', 'SCALAR'}
ODBC_DATETIME_LITERALS = {'d': <class 'sqlglot.expressions.Date'>, 't': <class 'sqlglot.expressions.Time'>, 'ts': <class 'sqlglot.expressions.Timestamp'>}
ON_CONDITION_TOKENS = {'EMPTY', 'FALSE', 'NULL', 'TRUE', 'ERROR'}
PRIVILEGE_FOLLOW_TOKENS = {<TokenType.COMMA: 'COMMA'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.ON: 'ON'>}
DESCRIBE_STYLES = {'ANALYZE', 'HISTORY', 'EXTENDED', 'FORMATTED'}
ANALYZE_STYLES = {'LOCAL', 'VERBOSE', 'SKIP_LOCKED', 'NO_WRITE_TO_BINLOG', 'BUFFER_USAGE_LIMIT', 'SAMPLE', 'FULL'}
ANALYZE_EXPRESSION_PARSERS = {'ALL': <function Parser.<lambda>>, 'COMPUTE': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'ESTIMATE': <function Parser.<lambda>>, 'LIST': <function Parser.<lambda>>, 'PREDICATE': <function Parser.<lambda>>, 'UPDATE': <function Parser.<lambda>>, 'VALIDATE': <function Parser.<lambda>>}
PARTITION_KEYWORDS = {'SUBPARTITION', 'PARTITION'}
AMBIGUOUS_ALIAS_TOKENS = (<TokenType.LIMIT: 'LIMIT'>, <TokenType.OFFSET: 'OFFSET'>)
OPERATION_MODIFIERS: Set[str] = set()
RECURSIVE_CTE_SEARCH_KIND = {'BREADTH', 'CYCLE', 'DEPTH'}
MODIFIABLES = (<class 'sqlglot.expressions.Query'>, <class 'sqlglot.expressions.Table'>, <class 'sqlglot.expressions.TableFromRows'>)
STRICT_CAST = True
PREFIXED_PIVOT_COLUMNS = False
IDENTIFY_PIVOT_STRINGS = False
LOG_DEFAULTS_TO_LN = False
TABLESAMPLE_CSV = False
DEFAULT_SAMPLING_METHOD: Optional[str] = None
SET_REQUIRES_ASSIGNMENT_DELIMITER = True
TRIM_PATTERN_FIRST = False
STRING_ALIASES = False
MODIFIERS_ATTACHED_TO_SET_OP = True
SET_OP_MODIFIERS = {'limit', 'order', 'offset'}
NO_PAREN_IF_COMMANDS = True
JSON_ARROWS_REQUIRE_JSON_TYPE = False
COLON_IS_VARIANT_EXTRACT = False
VALUES_FOLLOWED_BY_PAREN = True
SUPPORTS_IMPLICIT_UNNEST = False
INTERVAL_SPANS = True
SUPPORTS_PARTITION_SELECTION = False
WRAPPED_TRANSFORM_COLUMN_CONSTRAINT = True
OPTIONAL_ALIAS_TOKEN_CTE = True
ALTER_RENAME_REQUIRES_COLUMN = 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

    1549    def reset(self):
    1550        self.sql = ""
    1551        self.errors = []
    1552        self._tokens = []
    1553        self._index = 0
    1554        self._curr = None
    1555        self._next = None
    1556        self._prev = None
    1557        self._prev_comments = None
    1558        self._pipe_cte_counter = 0

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

    1560    def parse(
    1561        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    1562    ) -> t.List[t.Optional[exp.Expression]]:
    1563        """
    1564        Parses a list of tokens and returns a list of syntax trees, one tree
    1565        per parsed SQL statement.
    1566
    1567        Args:
    1568            raw_tokens: The list of tokens.
    1569            sql: The original SQL string, used to produce helpful debug messages.
    1570
    1571        Returns:
    1572            The list of the produced syntax trees.
    1573        """
    1574        return self._parse(
    1575            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    1576        )

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

    1578    def parse_into(
    1579        self,
    1580        expression_types: exp.IntoType,
    1581        raw_tokens: t.List[Token],
    1582        sql: t.Optional[str] = None,
    1583    ) -> t.List[t.Optional[exp.Expression]]:
    1584        """
    1585        Parses a list of tokens into a given Expression type. If a collection of Expression
    1586        types is given instead, this method will try to parse the token list into each one
    1587        of them, stopping at the first for which the parsing succeeds.
    1588
    1589        Args:
    1590            expression_types: The expression type(s) to try and parse the token list into.
    1591            raw_tokens: The list of tokens.
    1592            sql: The original SQL string, used to produce helpful debug messages.
    1593
    1594        Returns:
    1595            The target Expression.
    1596        """
    1597        errors = []
    1598        for expression_type in ensure_list(expression_types):
    1599            parser = self.EXPRESSION_PARSERS.get(expression_type)
    1600            if not parser:
    1601                raise TypeError(f"No parser registered for {expression_type}")
    1602
    1603            try:
    1604                return self._parse(parser, raw_tokens, sql)
    1605            except ParseError as e:
    1606                e.errors[0]["into_expression"] = expression_type
    1607                errors.append(e)
    1608
    1609        raise ParseError(
    1610            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    1611            errors=merge_errors(errors),
    1612        ) 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

    1652    def check_errors(self) -> None:
    1653        """Logs or raises any found errors, depending on the chosen error level setting."""
    1654        if self.error_level == ErrorLevel.WARN:
    1655            for error in self.errors:
    1656                logger.error(str(error))
    1657        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1658            raise ParseError(
    1659                concat_messages(self.errors, self.max_errors),
    1660                errors=merge_errors(self.errors),
    1661            )

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

    1663    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1664        """
    1665        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1666        error level setting.
    1667        """
    1668        token = token or self._curr or self._prev or Token.string("")
    1669        start = token.start
    1670        end = token.end + 1
    1671        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1672        highlight = self.sql[start:end]
    1673        end_context = self.sql[end : end + self.error_message_context]
    1674
    1675        error = ParseError.new(
    1676            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1677            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1678            description=message,
    1679            line=token.line,
    1680            col=token.col,
    1681            start_context=start_context,
    1682            highlight=highlight,
    1683            end_context=end_context,
    1684        )
    1685
    1686        if self.error_level == ErrorLevel.IMMEDIATE:
    1687            raise error
    1688
    1689        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

    1691    def expression(
    1692        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1693    ) -> E:
    1694        """
    1695        Creates a new, validated Expression.
    1696
    1697        Args:
    1698            exp_class: The expression class to instantiate.
    1699            comments: An optional list of comments to attach to the expression.
    1700            kwargs: The arguments to set for the expression along with their respective values.
    1701
    1702        Returns:
    1703            The target expression.
    1704        """
    1705        instance = exp_class(**kwargs)
    1706        instance.add_comments(comments) if comments else self._add_comments(instance)
    1707        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

    1714    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1715        """
    1716        Validates an Expression, making sure that all its mandatory arguments are set.
    1717
    1718        Args:
    1719            expression: The expression to validate.
    1720            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1721
    1722        Returns:
    1723            The validated expression.
    1724        """
    1725        if self.error_level != ErrorLevel.IGNORE:
    1726            for error_message in expression.error_messages(args):
    1727                self.raise_error(error_message)
    1728
    1729        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

    4706    def parse_set_operation(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
    4707        start = self._index
    4708        _, side_token, kind_token = self._parse_join_parts()
    4709
    4710        side = side_token.text if side_token else None
    4711        kind = kind_token.text if kind_token else None
    4712
    4713        if not self._match_set(self.SET_OPERATIONS):
    4714            self._retreat(start)
    4715            return None
    4716
    4717        token_type = self._prev.token_type
    4718
    4719        if token_type == TokenType.UNION:
    4720            operation: t.Type[exp.SetOperation] = exp.Union
    4721        elif token_type == TokenType.EXCEPT:
    4722            operation = exp.Except
    4723        else:
    4724            operation = exp.Intersect
    4725
    4726        comments = self._prev.comments
    4727
    4728        if self._match(TokenType.DISTINCT):
    4729            distinct: t.Optional[bool] = True
    4730        elif self._match(TokenType.ALL):
    4731            distinct = False
    4732        else:
    4733            distinct = self.dialect.SET_OP_DISTINCT_BY_DEFAULT[operation]
    4734            if distinct is None:
    4735                self.raise_error(f"Expected DISTINCT or ALL for {operation.__name__}")
    4736
    4737        by_name = self._match_text_seq("BY", "NAME") or self._match_text_seq(
    4738            "STRICT", "CORRESPONDING"
    4739        )
    4740        if self._match_text_seq("CORRESPONDING"):
    4741            by_name = True
    4742            if not side and not kind:
    4743                kind = "INNER"
    4744
    4745        on_column_list = None
    4746        if by_name and self._match_texts(("ON", "BY")):
    4747            on_column_list = self._parse_wrapped_csv(self._parse_column)
    4748
    4749        expression = self._parse_select(nested=True, parse_set_operation=False)
    4750
    4751        return self.expression(
    4752            operation,
    4753            comments=comments,
    4754            this=this,
    4755            distinct=distinct,
    4756            by_name=by_name,
    4757            expression=expression,
    4758            side=side,
    4759            kind=kind,
    4760            on=on_column_list,
    4761        )

errors
sql