sqlglot.parser API documentation

Edit on GitHub

# sqlglot.parser

View Source

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

logger = <Logger sqlglot (WARNING)>
OPTIONS_TYPE = typing.Dict[str, typing.Sequence[typing.Union[typing.Sequence[str], str]]]
TIME_ZONE_RE: Pattern[str] = re.compile(':.*?[a-zA-Z\\+\\-]')
def build_var_map(args: List) -> sqlglot.expressions.StarMap | sqlglot.expressions.VarMap: View Source

    32def build_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
    33    if len(args) == 1 and args[0].is_star:
    34        return exp.StarMap(this=args[0])
    35
    36    keys = []
    37    values = []
    38    for i in range(0, len(args), 2):
    39        keys.append(args[i])
    40        values.append(args[i + 1])
    41
    42    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

    45def build_like(args: t.List) -> exp.Escape | exp.Like:
    46    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
    47    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

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

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

    64def build_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
    65    # Default argument order is base, expression
    66    this = seq_get(args, 0)
    67    expression = seq_get(args, 1)
    68
    69    if expression:
    70        if not dialect.LOG_BASE_FIRST:
    71            this, expression = expression, this
    72        return exp.Log(this=this, expression=expression)
    73
    74    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

    77def build_hex(args: t.List, dialect: Dialect) -> exp.Hex | exp.LowerHex:
    78    arg = seq_get(args, 0)
    79    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

    82def build_lower(args: t.List) -> exp.Lower | exp.Hex:
    83    # LOWER(HEX(..)) can be simplified to LowerHex to simplify its transpilation
    84    arg = seq_get(args, 0)
    85    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

    88def build_upper(args: t.List) -> exp.Upper | exp.Hex:
    89    # UPPER(HEX(..)) can be simplified to Hex to simplify its transpilation
    90    arg = seq_get(args, 0)
    91    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

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

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

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

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

    118def build_pad(args: t.List, is_left: bool = True):
    119    return exp.Pad(
    120        this=seq_get(args, 0),
    121        expression=seq_get(args, 1),
    122        fill_pattern=seq_get(args, 2),
    123        is_left=is_left,
    124    )

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

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

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

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

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

    150def build_trim(args: t.List, is_left: bool = True):
    151    return exp.Trim(
    152        this=seq_get(args, 0),
    153        expression=seq_get(args, 1),
    154        position="LEADING" if is_left else "TRAILING",
    155    )

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

    158def build_coalesce(
    159    args: t.List, is_nvl: t.Optional[bool] = None, is_null: t.Optional[bool] = None
    160) -> exp.Coalesce:
    161    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

    164def build_locate_strposition(args: t.List):
    165    return exp.StrPosition(
    166        this=seq_get(args, 1),
    167        substr=seq_get(args, 0),
    168        position=seq_get(args, 2),
    169    )

class Parser: View Source

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

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

    1589    def __init__(
    1590        self,
    1591        error_level: t.Optional[ErrorLevel] = None,
    1592        error_message_context: int = 100,
    1593        max_errors: int = 3,
    1594        dialect: DialectType = None,
    1595    ):
    1596        from sqlglot.dialects import Dialect
    1597
    1598        self.error_level = error_level or ErrorLevel.IMMEDIATE
    1599        self.error_message_context = error_message_context
    1600        self.max_errors = max_errors
    1601        self.dialect = Dialect.get_or_raise(dialect)
    1602        self.reset()

FUNCTIONS: Dict[str, Callable] = {'AI_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AIAgg'>>, 'AI_CLASSIFY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AIClassify'>>, 'AI_SUMMARIZE_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AISummarizeAgg'>>, 'ABS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Abs'>>, 'ACOS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Acos'>>, 'ACOSH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Acosh'>>, '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_QUANTILES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxQuantiles'>>, 'APPROX_TOP_K': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxTopK'>>, 'APPROX_TOP_SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxTopSum'>>, '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_FIRST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayFirst'>>, '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_LAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayLast'>>, '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_REVERSE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayReverse'>>, '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_SLICE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySlice'>>, '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'>>, 'ASCII': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ascii'>>, 'ASIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Asin'>>, 'ASINH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Asinh'>>, 'ATAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Atan'>>, 'ATAN2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Atan2'>>, 'ATANH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Atanh'>>, 'AVG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Avg'>>, 'BASE64_DECODE_BINARY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Base64DecodeBinary'>>, 'BASE64_DECODE_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Base64DecodeString'>>, 'BASE64_ENCODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Base64Encode'>>, 'BIT_LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.BitLength'>>, 'BITWISE_AND_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.BitwiseAndAgg'>>, 'BITWISE_COUNT_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.BitwiseCountAgg'>>, 'BITWISE_OR_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.BitwiseOrAgg'>>, 'BITWISE_XOR_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.BitwiseXorAgg'>>, 'BYTE_LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ByteLength'>>, '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>, 'CODE_POINTS_TO_BYTES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CodePointsToBytes'>>, 'CODE_POINTS_TO_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CodePointsToString'>>, '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'>>, 'COMPRESS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Compress'>>, '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'>>, 'COSINE_DISTANCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CosineDistance'>>, 'COT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Cot'>>, 'COTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coth'>>, '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'>>, 'CSC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Csc'>>, 'CSCH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Csch'>>, 'CUME_DIST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CumeDist'>>, '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_TIMESTAMP_L_T_Z': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTimestampLTZ'>>, '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_FROM_UNIX_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromUnixDate'>>, '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'>>, 'DECODE_CASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DecodeCase'>>, 'DENSE_RANK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DenseRank'>>, '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'>>, 'EUCLIDEAN_DISTANCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.EuclideanDistance'>>, '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'>>, 'FARM_FINGERPRINT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FarmFingerprint'>>, 'FARMFINGERPRINT64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FarmFingerprint'>>, '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'>>, 'FLOAT64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Float64'>>, 'FLOOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Floor'>>, 'FORMAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Format'>>, 'FROM_BASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase'>>, 'FROM_BASE32': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase32'>>, '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_EMBEDDING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateEmbedding'>>, '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'>>, 'GET_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GetExtract'>>, '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'>>, 'GROUPING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Grouping'>>, 'HEX': <function build_hex>, 'HEX_DECODE_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.HexDecodeString'>>, 'HEX_ENCODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.HexEncode'>>, '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_APPEND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayAppend'>>, 'JSON_ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayContains'>>, 'JSON_ARRAY_INSERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayInsert'>>, 'JSONB_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBContains'>>, 'J_S_O_N_B_CONTAINS_ALL_TOP_KEYS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBContainsAllTopKeys'>>, 'J_S_O_N_B_CONTAINS_ANY_TOP_KEYS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBContainsAnyTopKeys'>>, 'J_S_O_N_B_DELETE_AT_PATH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBDeleteAtPath'>>, '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_BOOL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBool'>>, '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_KEYS_AT_DEPTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONKeysAtDepth'>>, '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'>>, 'JSON_REMOVE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONRemove'>>, 'JSON_SET': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONSet'>>, 'JSON_STRIP_NULLS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONStripNulls'>>, 'J_S_O_N_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONTable'>>, 'JSON_TYPE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONType'>>, 'J_S_O_N_VALUE_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONValueArray'>>, 'JUSTIFY_DAYS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JustifyDays'>>, 'JUSTIFY_HOURS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JustifyHours'>>, 'JUSTIFY_INTERVAL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JustifyInterval'>>, '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'>>, 'LAX_BOOL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LaxBool'>>, 'LAX_FLOAT64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LaxFloat64'>>, 'LAX_INT64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LaxInt64'>>, 'LAX_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LaxString'>>, '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'>>, 'M_D5_NUMBER_LOWER64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5NumberLower64'>>, 'M_D5_NUMBER_UPPER64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5NumberUpper64'>>, 'M_L_FORECAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MLForecast'>>, 'M_L_TRANSLATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MLTranslate'>>, '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'>>, 'NTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ntile'>>, '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_BIGNUMERIC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseBignumeric'>>, 'PARSE_DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseDatetime'>>, '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'>>, 'PARSE_NUMERIC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseNumeric'>>, 'PARSE_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseTime'>>, 'PERCENT_RANK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentRank'>>, '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_BUCKET': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RangeBucket'>>, 'RANGE_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RangeN'>>, 'RANK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rank'>>, '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_INSTR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpInstr'>>, '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'>>, 'REPLACE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Replace'>>, 'REVERSE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Reverse'>>, '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'>>, 'S_H_A1_DIGEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA1Digest'>>, 'SHA2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA2'>>, 'S_H_A2_DIGEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA2Digest'>>, 'SAFE_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeAdd'>>, 'SAFE_CONVERT_BYTES_TO_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeConvertBytesToString'>>, 'SAFE_DIVIDE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeDivide'>>, 'SAFE_MULTIPLY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeMultiply'>>, 'SAFE_NEGATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeNegate'>>, 'SAFE_SUBTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeSubtract'>>, 'SEC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sec'>>, 'SECH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sech'>>, 'SIGN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SIGNUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sin'>>, 'SINH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sinh'>>, 'SORT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SortArray'>>, 'SOUNDEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Soundex'>>, 'SPACE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Space'>>, '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'>>, 'SUBSTRING_INDEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SubstringIndex'>>, '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_BASE32': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToBase32'>>, '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_CODE_POINTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToCodePoints'>>, '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'>>, 'TRANSLATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Translate'>>, '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'>>, 'TYPEOF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Typeof'>>, '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_MICROS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixMicros'>>, 'UNIX_MILLIS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixMillis'>>, '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'>>, 'UTC_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UtcDate'>>, 'UTC_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UtcTime'>>, 'UTC_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UtcTimestamp'>>, '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'>>, 'VECTOR_SEARCH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VectorSearch'>>, '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.STRUCT: 'STRUCT'>, <TokenType.UNION: 'UNION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NESTED: 'NESTED'>}
NESTED_TYPE_TOKENS = {<TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.RANGE: 'RANGE'>, <TokenType.LIST: 'LIST'>, <TokenType.UNION: 'UNION'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.MAP: 'MAP'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NESTED: 'NESTED'>}
ENUM_TYPE_TOKENS = {<TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM16: 'ENUM16'>}
AGGREGATE_TYPE_TOKENS = {<TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>}
TYPE_TOKENS = {<TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.RANGE: 'RANGE'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT256: 'INT256'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.UINT: 'UINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NAME: 'NAME'>, <TokenType.UNION: 'UNION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DATE32: 'DATE32'>, <TokenType.DATE: 'DATE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.NULL: 'NULL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.ENUM: 'ENUM'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.BLOB: 'BLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VOID: 'VOID'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.GEOGRAPHYPOINT: 'GEOGRAPHYPOINT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.XML: 'XML'>, <TokenType.JSON: 'JSON'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TIME: 'TIME'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UUID: 'UUID'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.BIT: 'BIT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NESTED: 'NESTED'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.INET: 'INET'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.LIST: 'LIST'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MAP: 'MAP'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.POINT: 'POINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.RING: 'RING'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>}
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.LT: 'LT'>, <TokenType.COMMA: 'COMMA'>, <TokenType.AMP: 'AMP'>, <TokenType.PLUS: 'PLUS'>, <TokenType.CARET: 'CARET'>, <TokenType.COLON: 'COLON'>, <TokenType.DASH: 'DASH'>, <TokenType.TILDA: 'TILDA'>, <TokenType.SLASH: 'SLASH'>, <TokenType.GT: 'GT'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.MOD: 'MOD'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.SELECT: 'SELECT'>, <TokenType.PIPE: 'PIPE'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.STAR: 'STAR'>, <TokenType.HASH: 'HASH'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.NOT: 'NOT'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.EQ: 'EQ'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.DOT: 'DOT'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.R_PAREN: 'R_PAREN'>}
DB_CREATABLES = {<TokenType.SINK: 'SINK'>, <TokenType.SEMANTIC_VIEW: 'SEMANTIC_VIEW'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.STAGE: 'STAGE'>, <TokenType.TAG: 'TAG'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>}
CREATABLES = {<TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.STAGE: 'STAGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.MODEL: 'MODEL'>, <TokenType.SINK: 'SINK'>, <TokenType.SEMANTIC_VIEW: 'SEMANTIC_VIEW'>, <TokenType.INDEX: 'INDEX'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.TAG: 'TAG'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
ALTERABLES = {<TokenType.VIEW: 'VIEW'>, <TokenType.TABLE: 'TABLE'>, <TokenType.SESSION: 'SESSION'>, <TokenType.INDEX: 'INDEX'>}
ID_VAR_TOKENS = {<TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.CASE: 'CASE'>, <TokenType.STAGE: 'STAGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.APPLY: 'APPLY'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT256: 'INT256'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ROWS: 'ROWS'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.UINT: 'UINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.FALSE: 'FALSE'>, <TokenType.END: 'END'>, <TokenType.UINT256: 'UINT256'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NAME: 'NAME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DATE: 'DATE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SESSION: 'SESSION'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LOCK: 'LOCK'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ANY: 'ANY'>, <TokenType.KILL: 'KILL'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SINK: 'SINK'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TRUE: 'TRUE'>, <TokenType.NULL: 'NULL'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ENUM: 'ENUM'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.IS: 'IS'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.VAR: 'VAR'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.BLOB: 'BLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VOID: 'VOID'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.GEOGRAPHYPOINT: 'GEOGRAPHYPOINT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SEMANTIC_VIEW: 'SEMANTIC_VIEW'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ASOF: 'ASOF'>, <TokenType.DIV: 'DIV'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ROW: 'ROW'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.XML: 'XML'>, <TokenType.JSON: 'JSON'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIME: 'TIME'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.RENAME: 'RENAME'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UUID: 'UUID'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.BIT: 'BIT'>, <TokenType.GET: 'GET'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NESTED: 'NESTED'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.USE: 'USE'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TAG: 'TAG'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.INET: 'INET'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.COPY: 'COPY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.LIST: 'LIST'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ALL: 'ALL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.FULL: 'FULL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PUT: 'PUT'>, <TokenType.ASC: 'ASC'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MAP: 'MAP'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SHOW: 'SHOW'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.TOP: 'TOP'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.POINT: 'POINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DESC: 'DESC'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.DETACH: 'DETACH'>, <TokenType.SET: 'SET'>, <TokenType.RING: 'RING'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
TABLE_ALIAS_TOKENS = {<TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.CASE: 'CASE'>, <TokenType.STAGE: 'STAGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.APPLY: 'APPLY'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT256: 'INT256'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ROWS: 'ROWS'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.UINT: 'UINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.FALSE: 'FALSE'>, <TokenType.END: 'END'>, <TokenType.UINT256: 'UINT256'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NAME: 'NAME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DATE: 'DATE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SESSION: 'SESSION'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ANY: 'ANY'>, <TokenType.KILL: 'KILL'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SINK: 'SINK'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TRUE: 'TRUE'>, <TokenType.NULL: 'NULL'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ENUM: 'ENUM'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.IS: 'IS'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.VAR: 'VAR'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.BLOB: 'BLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VOID: 'VOID'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.GEOGRAPHYPOINT: 'GEOGRAPHYPOINT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SEMANTIC_VIEW: 'SEMANTIC_VIEW'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DIV: 'DIV'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ROW: 'ROW'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.XML: 'XML'>, <TokenType.JSON: 'JSON'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.TIME: 'TIME'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.RENAME: 'RENAME'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UUID: 'UUID'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.BIT: 'BIT'>, <TokenType.GET: 'GET'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NESTED: 'NESTED'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.USE: 'USE'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TAG: 'TAG'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.INET: 'INET'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.COPY: 'COPY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.LIST: 'LIST'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ALL: 'ALL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PUT: 'PUT'>, <TokenType.ASC: 'ASC'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MAP: 'MAP'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SHOW: 'SHOW'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.TOP: 'TOP'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.POINT: 'POINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DESC: 'DESC'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.DETACH: 'DETACH'>, <TokenType.SET: 'SET'>, <TokenType.RING: 'RING'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
ALIAS_TOKENS = {<TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.CASE: 'CASE'>, <TokenType.STAGE: 'STAGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.APPLY: 'APPLY'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT256: 'INT256'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ROWS: 'ROWS'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.UINT: 'UINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.FALSE: 'FALSE'>, <TokenType.END: 'END'>, <TokenType.UINT256: 'UINT256'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NAME: 'NAME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DATE: 'DATE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SESSION: 'SESSION'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LOCK: 'LOCK'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ANY: 'ANY'>, <TokenType.KILL: 'KILL'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SINK: 'SINK'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TRUE: 'TRUE'>, <TokenType.NULL: 'NULL'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ENUM: 'ENUM'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.IS: 'IS'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.VAR: 'VAR'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.BLOB: 'BLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VOID: 'VOID'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.GEOGRAPHYPOINT: 'GEOGRAPHYPOINT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SEMANTIC_VIEW: 'SEMANTIC_VIEW'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ASOF: 'ASOF'>, <TokenType.DIV: 'DIV'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ROW: 'ROW'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.XML: 'XML'>, <TokenType.JSON: 'JSON'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIME: 'TIME'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.RENAME: 'RENAME'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UUID: 'UUID'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.BIT: 'BIT'>, <TokenType.GET: 'GET'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NESTED: 'NESTED'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.USE: 'USE'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TAG: 'TAG'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.INET: 'INET'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.COPY: 'COPY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.LIST: 'LIST'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ALL: 'ALL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.FULL: 'FULL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PUT: 'PUT'>, <TokenType.ASC: 'ASC'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MAP: 'MAP'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SHOW: 'SHOW'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.TOP: 'TOP'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.POINT: 'POINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DESC: 'DESC'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.DETACH: 'DETACH'>, <TokenType.SET: 'SET'>, <TokenType.RING: 'RING'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
COLON_PLACEHOLDER_TOKENS = {<TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.CASE: 'CASE'>, <TokenType.STAGE: 'STAGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.APPLY: 'APPLY'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT256: 'INT256'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ROWS: 'ROWS'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.UINT: 'UINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.FALSE: 'FALSE'>, <TokenType.END: 'END'>, <TokenType.UINT256: 'UINT256'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NAME: 'NAME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DATE: 'DATE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SESSION: 'SESSION'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LOCK: 'LOCK'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ANY: 'ANY'>, <TokenType.KILL: 'KILL'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SINK: 'SINK'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TRUE: 'TRUE'>, <TokenType.NULL: 'NULL'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ENUM: 'ENUM'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.IS: 'IS'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.VAR: 'VAR'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.BLOB: 'BLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VOID: 'VOID'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.GEOGRAPHYPOINT: 'GEOGRAPHYPOINT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SEMANTIC_VIEW: 'SEMANTIC_VIEW'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ASOF: 'ASOF'>, <TokenType.DIV: 'DIV'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ROW: 'ROW'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.XML: 'XML'>, <TokenType.JSON: 'JSON'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIME: 'TIME'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.RENAME: 'RENAME'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UUID: 'UUID'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.BIT: 'BIT'>, <TokenType.GET: 'GET'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NESTED: 'NESTED'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.USE: 'USE'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TAG: 'TAG'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.INET: 'INET'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.COPY: 'COPY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.LIST: 'LIST'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ALL: 'ALL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.FULL: 'FULL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PUT: 'PUT'>, <TokenType.ASC: 'ASC'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MAP: 'MAP'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SHOW: 'SHOW'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.TOP: 'TOP'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.POINT: 'POINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DESC: 'DESC'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.DETACH: 'DETACH'>, <TokenType.SET: 'SET'>, <TokenType.RING: 'RING'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
ARRAY_CONSTRUCTORS = {'ARRAY': <class 'sqlglot.expressions.Array'>, 'LIST': <class 'sqlglot.expressions.List'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.CASE: 'CASE'>, <TokenType.STAGE: 'STAGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.APPLY: 'APPLY'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT256: 'INT256'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ROWS: 'ROWS'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.UINT: 'UINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.FALSE: 'FALSE'>, <TokenType.END: 'END'>, <TokenType.UINT256: 'UINT256'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NAME: 'NAME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DATE: 'DATE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SESSION: 'SESSION'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ANY: 'ANY'>, <TokenType.KILL: 'KILL'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SINK: 'SINK'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TRUE: 'TRUE'>, <TokenType.NULL: 'NULL'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ENUM: 'ENUM'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.VAR: 'VAR'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.BLOB: 'BLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VOID: 'VOID'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.GEOGRAPHYPOINT: 'GEOGRAPHYPOINT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SEMANTIC_VIEW: 'SEMANTIC_VIEW'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DIV: 'DIV'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ROW: 'ROW'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.XML: 'XML'>, <TokenType.JSON: 'JSON'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.TIME: 'TIME'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.RENAME: 'RENAME'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UUID: 'UUID'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.BIT: 'BIT'>, <TokenType.GET: 'GET'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NESTED: 'NESTED'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.USE: 'USE'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TAG: 'TAG'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.INET: 'INET'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.COPY: 'COPY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.LIST: 'LIST'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ALL: 'ALL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PUT: 'PUT'>, <TokenType.ASC: 'ASC'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MAP: 'MAP'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SHOW: 'SHOW'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.TOP: 'TOP'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.POINT: 'POINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DESC: 'DESC'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.DETACH: 'DETACH'>, <TokenType.SET: 'SET'>, <TokenType.RING: 'RING'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
UPDATE_ALIAS_TOKENS = {<TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.CASE: 'CASE'>, <TokenType.STAGE: 'STAGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.APPLY: 'APPLY'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT256: 'INT256'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ROWS: 'ROWS'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.UINT: 'UINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.FALSE: 'FALSE'>, <TokenType.END: 'END'>, <TokenType.UINT256: 'UINT256'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NAME: 'NAME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DATE: 'DATE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SESSION: 'SESSION'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ANY: 'ANY'>, <TokenType.KILL: 'KILL'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SINK: 'SINK'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TRUE: 'TRUE'>, <TokenType.NULL: 'NULL'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ENUM: 'ENUM'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.IS: 'IS'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.VAR: 'VAR'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.BLOB: 'BLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VOID: 'VOID'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.GEOGRAPHYPOINT: 'GEOGRAPHYPOINT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SEMANTIC_VIEW: 'SEMANTIC_VIEW'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DIV: 'DIV'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ROW: 'ROW'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.XML: 'XML'>, <TokenType.JSON: 'JSON'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.TIME: 'TIME'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.RENAME: 'RENAME'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UUID: 'UUID'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.BIT: 'BIT'>, <TokenType.GET: 'GET'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NESTED: 'NESTED'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.USE: 'USE'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TAG: 'TAG'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.INET: 'INET'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.COPY: 'COPY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.LIST: 'LIST'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ALL: 'ALL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PUT: 'PUT'>, <TokenType.ASC: 'ASC'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MAP: 'MAP'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SHOW: 'SHOW'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.TOP: 'TOP'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.POINT: 'POINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DESC: 'DESC'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.DETACH: 'DETACH'>, <TokenType.RING: 'RING'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
TRIM_TYPES = {'TRAILING', 'LEADING', 'BOTH'}
FUNC_TOKENS = {<TokenType.INSERT: 'INSERT'>, <TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT256: 'INT256'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.UINT: 'UINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UINT256: 'UINT256'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.UTC_DATE: 'UTC_DATE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NAME: 'NAME'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.UNION: 'UNION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DATE: 'DATE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ANY: 'ANY'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.NULL: 'NULL'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.ENUM: 'ENUM'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.VAR: 'VAR'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.BLOB: 'BLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VOID: 'VOID'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.GEOGRAPHYPOINT: 'GEOGRAPHYPOINT'>, <TokenType.UTC_TIMESTAMP: 'UTC_TIMESTAMP'>, <TokenType.NEXT: 'NEXT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.ROW: 'ROW'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.XML: 'XML'>, <TokenType.JSON: 'JSON'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.MERGE: 'MERGE'>, <TokenType.TIME: 'TIME'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UUID: 'UUID'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.BIT: 'BIT'>, <TokenType.GET: 'GET'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NESTED: 'NESTED'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.LIKE: 'LIKE'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.INET: 'INET'>, <TokenType.SUPER: 'SUPER'>, <TokenType.XOR: 'XOR'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.LIST: 'LIST'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ALL: 'ALL'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MAP: 'MAP'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.POINT: 'POINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.GLOB: 'GLOB'>, <TokenType.RING: 'RING'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UTC_TIME: 'UTC_TIME'>}
CONJUNCTION: Dict[sqlglot.tokens.TokenType, Type[sqlglot.expressions.Expression]] = {<TokenType.AND: 'AND'>: <class 'sqlglot.expressions.And'>}
ASSIGNMENT: Dict[sqlglot.tokens.TokenType, Type[sqlglot.expressions.Expression]] = {<TokenType.COLON_EQ: 'COLON_EQ'>: <class 'sqlglot.expressions.PropertyEQ'>}
DISJUNCTION: Dict[sqlglot.tokens.TokenType, Type[sqlglot.expressions.Expression]] = {<TokenType.OR: 'OR'>: <class 'sqlglot.expressions.Or'>}
EQUALITY = {<TokenType.EQ: 'EQ'>: <class 'sqlglot.expressions.EQ'>, <TokenType.NEQ: 'NEQ'>: <class 'sqlglot.expressions.NEQ'>, <TokenType.NULLSAFE_EQ: 'NULLSAFE_EQ'>: <class 'sqlglot.expressions.NullSafeEQ'>}
COMPARISON = {<TokenType.GT: 'GT'>: <class 'sqlglot.expressions.GT'>, <TokenType.GTE: 'GTE'>: <class 'sqlglot.expressions.GTE'>, <TokenType.LT: 'LT'>: <class 'sqlglot.expressions.LT'>, <TokenType.LTE: 'LTE'>: <class 'sqlglot.expressions.LTE'>}
BITWISE = {<TokenType.AMP: 'AMP'>: <class 'sqlglot.expressions.BitwiseAnd'>, <TokenType.CARET: 'CARET'>: <class 'sqlglot.expressions.BitwiseXor'>, <TokenType.PIPE: 'PIPE'>: <class 'sqlglot.expressions.BitwiseOr'>}
TERM = {<TokenType.DASH: 'DASH'>: <class 'sqlglot.expressions.Sub'>, <TokenType.PLUS: 'PLUS'>: <class 'sqlglot.expressions.Add'>, <TokenType.MOD: 'MOD'>: <class 'sqlglot.expressions.Mod'>, <TokenType.COLLATE: 'COLLATE'>: <class 'sqlglot.expressions.Collate'>}
FACTOR = {<TokenType.DIV: 'DIV'>: <class 'sqlglot.expressions.IntDiv'>, <TokenType.LR_ARROW: 'LR_ARROW'>: <class 'sqlglot.expressions.Distance'>, <TokenType.SLASH: 'SLASH'>: <class 'sqlglot.expressions.Div'>, <TokenType.STAR: 'STAR'>: <class 'sqlglot.expressions.Mul'>}
EXPONENT: Dict[sqlglot.tokens.TokenType, Type[sqlglot.expressions.Expression]] = {}
TIMES = {<TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIME: 'TIME'>}
TIMESTAMPS = {<TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIME: 'TIME'>}
SET_OPERATIONS = {<TokenType.EXCEPT: 'EXCEPT'>, <TokenType.UNION: 'UNION'>, <TokenType.INTERSECT: 'INTERSECT'>}
JOIN_METHODS = {<TokenType.ASOF: 'ASOF'>, <TokenType.POSITIONAL: 'POSITIONAL'>, <TokenType.NATURAL: 'NATURAL'>}
JOIN_SIDES = {<TokenType.RIGHT: 'RIGHT'>, <TokenType.FULL: 'FULL'>, <TokenType.LEFT: 'LEFT'>}
JOIN_KINDS = {<TokenType.STRAIGHT_JOIN: 'STRAIGHT_JOIN'>, <TokenType.CROSS: 'CROSS'>, <TokenType.SEMI: 'SEMI'>, <TokenType.INNER: 'INNER'>, <TokenType.ANTI: 'ANTI'>, <TokenType.OUTER: 'OUTER'>}
JOIN_HINTS: Set[str] = set()
LAMBDAS = {<TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.FARROW: 'FARROW'>: <function Parser.<lambda>>}
COLUMN_OPERATORS = {<TokenType.DOT: 'DOT'>: None, <TokenType.DOTCOLON: 'DOTCOLON'>: <function Parser.<lambda>>, <TokenType.DCOLON: 'DCOLON'>: <function Parser.<lambda>>, <TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.DARROW: 'DARROW'>: <function Parser.<lambda>>, <TokenType.HASH_ARROW: 'HASH_ARROW'>: <function Parser.<lambda>>, <TokenType.DHASH_ARROW: 'DHASH_ARROW'>: <function Parser.<lambda>>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>}
CAST_COLUMN_OPERATORS = {<TokenType.DCOLON: 'DCOLON'>, <TokenType.DOTCOLON: 'DOTCOLON'>}
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.REVOKE: 'REVOKE'>: <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>>, <TokenType.QMARK_AMP: 'QMARK_AMP'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.QMARK_PIPE: 'QMARK_PIPE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.HASH_DASH: 'HASH_DASH'>: <function binary_range_parser.<locals>._parse_binary_range>}
PIPE_SYNTAX_TRANSFORM_PARSERS = {'AGGREGATE': <function Parser.<lambda>>, 'AS': <function Parser.<lambda>>, 'EXTEND': <function Parser.<lambda>>, 'LIMIT': <function Parser.<lambda>>, 'ORDER BY': <function Parser.<lambda>>, 'PIVOT': <function Parser.<lambda>>, 'SELECT': <function Parser.<lambda>>, 'TABLESAMPLE': <function Parser.<lambda>>, 'UNPIVOT': <function Parser.<lambda>>, 'WHERE': <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 = {'WATERMARK', 'LIKE', 'UNIQUE', 'PRIMARY KEY', 'BUCKET', 'PERIOD', 'EXCLUDE', 'TRUNCATE', 'CHECK', 'FOREIGN KEY'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STRING: 'STRING'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
KEY_VALUE_DEFINITIONS = (<class 'sqlglot.expressions.Alias'>, <class 'sqlglot.expressions.EQ'>, <class 'sqlglot.expressions.PropertyEQ'>, <class 'sqlglot.expressions.Slice'>)
FUNCTION_PARSERS = {'ARG_MAX': <function Parser.<dictcomp>.<lambda>>, 'ARGMAX': <function Parser.<dictcomp>.<lambda>>, 'MAX_BY': <function Parser.<dictcomp>.<lambda>>, 'ARG_MIN': <function Parser.<dictcomp>.<lambda>>, 'ARGMIN': <function Parser.<dictcomp>.<lambda>>, 'MIN_BY': <function Parser.<dictcomp>.<lambda>>, 'CAST': <function Parser.<lambda>>, 'CEIL': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'FLOOR': <function Parser.<lambda>>, 'GAP_FILL': <function Parser.<lambda>>, 'JSON_OBJECT': <function Parser.<lambda>>, 'JSON_OBJECTAGG': <function Parser.<lambda>>, 'JSON_TABLE': <function Parser.<lambda>>, 'MATCH': <function Parser.<lambda>>, 'NORMALIZE': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'OVERLAY': <function Parser.<lambda>>, 'POSITION': <function Parser.<lambda>>, '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>>}
QUERY_MODIFIER_TOKENS = {<TokenType.LOCK: 'LOCK'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.ORDER_BY: 'ORDER_BY'>, <TokenType.PREWHERE: 'PREWHERE'>, <TokenType.QUALIFY: 'QUALIFY'>, <TokenType.START_WITH: 'START_WITH'>, <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>, <TokenType.GROUP_BY: 'GROUP_BY'>, <TokenType.CONNECT_BY: 'CONNECT_BY'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.WHERE: 'WHERE'>, <TokenType.HAVING: 'HAVING'>, <TokenType.MATCH_RECOGNIZE: 'MATCH_RECOGNIZE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.FOR: 'FOR'>, <TokenType.SORT_BY: 'SORT_BY'>, <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>, <TokenType.CLUSTER_BY: 'CLUSTER_BY'>, <TokenType.FETCH: 'FETCH'>, <TokenType.USING: 'USING'>}
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.L_PAREN: 'L_PAREN'>, <TokenType.WITH: 'WITH'>}
PRE_VOLATILE_TOKENS = {<TokenType.CREATE: 'CREATE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REPLACE: 'REPLACE'>}
TRANSACTION_KIND = {'EXCLUSIVE', 'IMMEDIATE', '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 = {'IGNORE', 'ROLLBACK', 'ABORT', 'FAIL', 'REPLACE'}
CLONE_KEYWORDS = {'COPY', 'CLONE'}
HISTORICAL_DATA_PREFIX = {'AT', 'END', 'BEFORE'}
HISTORICAL_DATA_KIND = {'STATEMENT', 'TIMESTAMP', 'OFFSET', 'VERSION', 'STREAM'}
OPCLASS_FOLLOW_KEYWORDS = {'WITH', 'DESC', 'NULLS', 'ASC'}
OPTYPE_FOLLOW_TOKENS = {<TokenType.COMMA: 'COMMA'>, <TokenType.R_PAREN: 'R_PAREN'>}
TABLE_INDEX_HINT_TOKENS = {<TokenType.IGNORE: 'IGNORE'>, <TokenType.USE: 'USE'>, <TokenType.FORCE: 'FORCE'>}
VIEW_ATTRIBUTES = {'ENCRYPTION', 'SCHEMABINDING', 'VIEW_METADATA'}
WINDOW_ALIAS_TOKENS = {<TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.CASE: 'CASE'>, <TokenType.STAGE: 'STAGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.APPLY: 'APPLY'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT256: 'INT256'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.UINT: 'UINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.FALSE: 'FALSE'>, <TokenType.END: 'END'>, <TokenType.UINT256: 'UINT256'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NAME: 'NAME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DATE: 'DATE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SESSION: 'SESSION'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LOCK: 'LOCK'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ANY: 'ANY'>, <TokenType.KILL: 'KILL'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SINK: 'SINK'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TRUE: 'TRUE'>, <TokenType.NULL: 'NULL'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ENUM: 'ENUM'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.IS: 'IS'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.VAR: 'VAR'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.BLOB: 'BLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VOID: 'VOID'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.GEOGRAPHYPOINT: 'GEOGRAPHYPOINT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SEMANTIC_VIEW: 'SEMANTIC_VIEW'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ASOF: 'ASOF'>, <TokenType.DIV: 'DIV'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ROW: 'ROW'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.XML: 'XML'>, <TokenType.JSON: 'JSON'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIME: 'TIME'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.RENAME: 'RENAME'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UUID: 'UUID'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.BIT: 'BIT'>, <TokenType.GET: 'GET'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NESTED: 'NESTED'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.USE: 'USE'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TAG: 'TAG'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.INET: 'INET'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.COPY: 'COPY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.LIST: 'LIST'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ALL: 'ALL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.FULL: 'FULL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PUT: 'PUT'>, <TokenType.ASC: 'ASC'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MAP: 'MAP'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SHOW: 'SHOW'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.TOP: 'TOP'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.POINT: 'POINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DESC: 'DESC'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.DETACH: 'DETACH'>, <TokenType.SET: 'SET'>, <TokenType.RING: 'RING'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'FOLLOWING', 'PRECEDING'}
JSON_KEY_VALUE_SEPARATOR_TOKENS = {<TokenType.IS: 'IS'>, <TokenType.COMMA: 'COMMA'>, <TokenType.COLON: 'COLON'>}
FETCH_TOKENS = {<TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.CASE: 'CASE'>, <TokenType.STAGE: 'STAGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.APPLY: 'APPLY'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT256: 'INT256'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.UINT: 'UINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.FALSE: 'FALSE'>, <TokenType.END: 'END'>, <TokenType.UINT256: 'UINT256'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NAME: 'NAME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DATE: 'DATE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SESSION: 'SESSION'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LOCK: 'LOCK'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ANY: 'ANY'>, <TokenType.KILL: 'KILL'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SINK: 'SINK'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TRUE: 'TRUE'>, <TokenType.NULL: 'NULL'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ENUM: 'ENUM'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.IS: 'IS'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.LEFT: 'LEFT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.VAR: 'VAR'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.BLOB: 'BLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VOID: 'VOID'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.GEOGRAPHYPOINT: 'GEOGRAPHYPOINT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SEMANTIC_VIEW: 'SEMANTIC_VIEW'>, <TokenType.FILTER: 'FILTER'>, <TokenType.ASOF: 'ASOF'>, <TokenType.DIV: 'DIV'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.XML: 'XML'>, <TokenType.JSON: 'JSON'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIME: 'TIME'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.RENAME: 'RENAME'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UUID: 'UUID'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.BIT: 'BIT'>, <TokenType.GET: 'GET'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NESTED: 'NESTED'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.USE: 'USE'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TAG: 'TAG'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.INET: 'INET'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.COPY: 'COPY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.LIST: 'LIST'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ALL: 'ALL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.FULL: 'FULL'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PUT: 'PUT'>, <TokenType.ASC: 'ASC'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MAP: 'MAP'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SHOW: 'SHOW'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.TOP: 'TOP'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.POINT: 'POINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DESC: 'DESC'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.DETACH: 'DETACH'>, <TokenType.SET: 'SET'>, <TokenType.RING: 'RING'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.INDEX: 'INDEX'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.KEY: 'KEY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.INT: 'INT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.RANGE: 'RANGE'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.CASE: 'CASE'>, <TokenType.STAGE: 'STAGE'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.APPLY: 'APPLY'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT256: 'INT256'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.LOAD: 'LOAD'>, <TokenType.ROWS: 'ROWS'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.UINT: 'UINT'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.INT128: 'INT128'>, <TokenType.FALSE: 'FALSE'>, <TokenType.END: 'END'>, <TokenType.UINT256: 'UINT256'>, <TokenType.EXPORT: 'EXPORT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NAME: 'NAME'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DATE: 'DATE'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SESSION: 'SESSION'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ANY: 'ANY'>, <TokenType.KILL: 'KILL'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.SINK: 'SINK'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TRUE: 'TRUE'>, <TokenType.NULL: 'NULL'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.ENUM: 'ENUM'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.IS: 'IS'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.VAR: 'VAR'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.BLOB: 'BLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.VOID: 'VOID'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.GEOGRAPHYPOINT: 'GEOGRAPHYPOINT'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SEMANTIC_VIEW: 'SEMANTIC_VIEW'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DIV: 'DIV'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.ROW: 'ROW'>, <TokenType.TEXT: 'TEXT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.XML: 'XML'>, <TokenType.JSON: 'JSON'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SOME: 'SOME'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.TIME: 'TIME'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.RENAME: 'RENAME'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.UUID: 'UUID'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.BIT: 'BIT'>, <TokenType.GET: 'GET'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NESTED: 'NESTED'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.USE: 'USE'>, <TokenType.UDOUBLE: 'UDOUBLE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.TAG: 'TAG'>, <TokenType.NOTHING: 'NOTHING'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.FILE_FORMAT: 'FILE_FORMAT'>, <TokenType.INET: 'INET'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.SUPER: 'SUPER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.COPY: 'COPY'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.LIST: 'LIST'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.YEAR: 'YEAR'>, <TokenType.ALL: 'ALL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.PUT: 'PUT'>, <TokenType.ASC: 'ASC'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MAP: 'MAP'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.MONEY: 'MONEY'>, <TokenType.CURRENT_SCHEMA: 'CURRENT_SCHEMA'>, <TokenType.JSONB: 'JSONB'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SHOW: 'SHOW'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.TOP: 'TOP'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.POINT: 'POINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.DESC: 'DESC'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.DETACH: 'DETACH'>, <TokenType.SET: 'SET'>, <TokenType.RING: 'RING'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.CHAR: 'CHAR'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
SELECT_START_TOKENS = {<TokenType.SELECT: 'SELECT'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.WITH: 'WITH'>}
COPY_INTO_VARLEN_OPTIONS = {'COPY_OPTIONS', 'CREDENTIAL', 'FORMAT_OPTIONS', 'FILE_FORMAT'}
IS_JSON_PREDICATE_KIND = {'ARRAY', 'VALUE', 'OBJECT', 'SCALAR'}
ODBC_DATETIME_LITERALS = {'d': <class 'sqlglot.expressions.Date'>, 't': <class 'sqlglot.expressions.Time'>, 'ts': <class 'sqlglot.expressions.Timestamp'>}
ON_CONDITION_TOKENS = {'FALSE', 'TRUE', 'NULL', 'ERROR', 'EMPTY'}
PRIVILEGE_FOLLOW_TOKENS = {<TokenType.COMMA: 'COMMA'>, <TokenType.ON: 'ON'>, <TokenType.L_PAREN: 'L_PAREN'>}
DESCRIBE_STYLES = {'HISTORY', 'ANALYZE', 'FORMATTED', 'EXTENDED'}
ANALYZE_STYLES = {'FULL', 'LOCAL', 'SKIP_LOCKED', 'VERBOSE', 'SAMPLE', 'BUFFER_USAGE_LIMIT', 'NO_WRITE_TO_BINLOG'}
ANALYZE_EXPRESSION_PARSERS = {'ALL': <function Parser.<lambda>>, 'COMPUTE': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'ESTIMATE': <function Parser.<lambda>>, 'LIST': <function Parser.<lambda>>, 'PREDICATE': <function Parser.<lambda>>, 'UPDATE': <function Parser.<lambda>>, 'VALIDATE': <function Parser.<lambda>>}
PARTITION_KEYWORDS = {'PARTITION', 'SUBPARTITION'}
AMBIGUOUS_ALIAS_TOKENS = (<TokenType.LIMIT: 'LIMIT'>, <TokenType.OFFSET: 'OFFSET'>)
OPERATION_MODIFIERS: Set[str] = set()
RECURSIVE_CTE_SEARCH_KIND = {'CYCLE', 'DEPTH', 'BREADTH'}
MODIFIABLES = (<class 'sqlglot.expressions.Query'>, <class 'sqlglot.expressions.Table'>, <class 'sqlglot.expressions.TableFromRows'>)
STRICT_CAST = True
PREFIXED_PIVOT_COLUMNS = False
IDENTIFY_PIVOT_STRINGS = False
LOG_DEFAULTS_TO_LN = False
TABLESAMPLE_CSV = False
DEFAULT_SAMPLING_METHOD: Optional[str] = None
SET_REQUIRES_ASSIGNMENT_DELIMITER = True
TRIM_PATTERN_FIRST = False
STRING_ALIASES = False
MODIFIERS_ATTACHED_TO_SET_OP = True
SET_OP_MODIFIERS = {'order', 'offset', 'limit'}
NO_PAREN_IF_COMMANDS = True
JSON_ARROWS_REQUIRE_JSON_TYPE = False
COLON_IS_VARIANT_EXTRACT = False
VALUES_FOLLOWED_BY_PAREN = True
SUPPORTS_IMPLICIT_UNNEST = False
INTERVAL_SPANS = True
SUPPORTS_PARTITION_SELECTION = False
WRAPPED_TRANSFORM_COLUMN_CONSTRAINT = True
OPTIONAL_ALIAS_TOKEN_CTE = True
ALTER_RENAME_REQUIRES_COLUMN = True
JOINS_HAVE_EQUAL_PRECEDENCE = False
ZONE_AWARE_TIMESTAMP_CONSTRUCTOR = False
MAP_KEYS_ARE_ARBITRARY_EXPRESSIONS = False
JSON_EXTRACT_REQUIRES_JSON_EXPRESSION = False
ADD_JOIN_ON_TRUE = False
SUPPORTS_OMITTED_INTERVAL_SPAN_UNIT = False
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

    1604    def reset(self):
    1605        self.sql = ""
    1606        self.errors = []
    1607        self._tokens = []
    1608        self._index = 0
    1609        self._curr = None
    1610        self._next = None
    1611        self._prev = None
    1612        self._prev_comments = None
    1613        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

    1615    def parse(
    1616        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    1617    ) -> t.List[t.Optional[exp.Expression]]:
    1618        """
    1619        Parses a list of tokens and returns a list of syntax trees, one tree
    1620        per parsed SQL statement.
    1621
    1622        Args:
    1623            raw_tokens: The list of tokens.
    1624            sql: The original SQL string, used to produce helpful debug messages.
    1625
    1626        Returns:
    1627            The list of the produced syntax trees.
    1628        """
    1629        return self._parse(
    1630            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    1631        )

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

    1633    def parse_into(
    1634        self,
    1635        expression_types: exp.IntoType,
    1636        raw_tokens: t.List[Token],
    1637        sql: t.Optional[str] = None,
    1638    ) -> t.List[t.Optional[exp.Expression]]:
    1639        """
    1640        Parses a list of tokens into a given Expression type. If a collection of Expression
    1641        types is given instead, this method will try to parse the token list into each one
    1642        of them, stopping at the first for which the parsing succeeds.
    1643
    1644        Args:
    1645            expression_types: The expression type(s) to try and parse the token list into.
    1646            raw_tokens: The list of tokens.
    1647            sql: The original SQL string, used to produce helpful debug messages.
    1648
    1649        Returns:
    1650            The target Expression.
    1651        """
    1652        errors = []
    1653        for expression_type in ensure_list(expression_types):
    1654            parser = self.EXPRESSION_PARSERS.get(expression_type)
    1655            if not parser:
    1656                raise TypeError(f"No parser registered for {expression_type}")
    1657
    1658            try:
    1659                return self._parse(parser, raw_tokens, sql)
    1660            except ParseError as e:
    1661                e.errors[0]["into_expression"] = expression_type
    1662                errors.append(e)
    1663
    1664        raise ParseError(
    1665            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    1666            errors=merge_errors(errors),
    1667        ) 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

    1707    def check_errors(self) -> None:
    1708        """Logs or raises any found errors, depending on the chosen error level setting."""
    1709        if self.error_level == ErrorLevel.WARN:
    1710            for error in self.errors:
    1711                logger.error(str(error))
    1712        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1713            raise ParseError(
    1714                concat_messages(self.errors, self.max_errors),
    1715                errors=merge_errors(self.errors),
    1716            )

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

    1718    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1719        """
    1720        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1721        error level setting.
    1722        """
    1723        token = token or self._curr or self._prev or Token.string("")
    1724        start = token.start
    1725        end = token.end + 1
    1726        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1727        highlight = self.sql[start:end]
    1728        end_context = self.sql[end : end + self.error_message_context]
    1729
    1730        error = ParseError.new(
    1731            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1732            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1733            description=message,
    1734            line=token.line,
    1735            col=token.col,
    1736            start_context=start_context,
    1737            highlight=highlight,
    1738            end_context=end_context,
    1739        )
    1740
    1741        if self.error_level == ErrorLevel.IMMEDIATE:
    1742            raise error
    1743
    1744        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

    1746    def expression(
    1747        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1748    ) -> E:
    1749        """
    1750        Creates a new, validated Expression.
    1751
    1752        Args:
    1753            exp_class: The expression class to instantiate.
    1754            comments: An optional list of comments to attach to the expression.
    1755            kwargs: The arguments to set for the expression along with their respective values.
    1756
    1757        Returns:
    1758            The target expression.
    1759        """
    1760        instance = exp_class(**kwargs)
    1761        instance.add_comments(comments) if comments else self._add_comments(instance)
    1762        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

    1769    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1770        """
    1771        Validates an Expression, making sure that all its mandatory arguments are set.
    1772
    1773        Args:
    1774            expression: The expression to validate.
    1775            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1776
    1777        Returns:
    1778            The validated expression.
    1779        """
    1780        if self.error_level != ErrorLevel.IGNORE:
    1781            for error_message in expression.error_messages(args):
    1782                self.raise_error(error_message)
    1783
    1784        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], consume_pipe: bool = False) -> Optional[sqlglot.expressions.Expression]: View Source

    4867    def parse_set_operation(
    4868        self, this: t.Optional[exp.Expression], consume_pipe: bool = False
    4869    ) -> t.Optional[exp.Expression]:
    4870        start = self._index
    4871        _, side_token, kind_token = self._parse_join_parts()
    4872
    4873        side = side_token.text if side_token else None
    4874        kind = kind_token.text if kind_token else None
    4875
    4876        if not self._match_set(self.SET_OPERATIONS):
    4877            self._retreat(start)
    4878            return None
    4879
    4880        token_type = self._prev.token_type
    4881
    4882        if token_type == TokenType.UNION:
    4883            operation: t.Type[exp.SetOperation] = exp.Union
    4884        elif token_type == TokenType.EXCEPT:
    4885            operation = exp.Except
    4886        else:
    4887            operation = exp.Intersect
    4888
    4889        comments = self._prev.comments
    4890
    4891        if self._match(TokenType.DISTINCT):
    4892            distinct: t.Optional[bool] = True
    4893        elif self._match(TokenType.ALL):
    4894            distinct = False
    4895        else:
    4896            distinct = self.dialect.SET_OP_DISTINCT_BY_DEFAULT[operation]
    4897            if distinct is None:
    4898                self.raise_error(f"Expected DISTINCT or ALL for {operation.__name__}")
    4899
    4900        by_name = self._match_text_seq("BY", "NAME") or self._match_text_seq(
    4901            "STRICT", "CORRESPONDING"
    4902        )
    4903        if self._match_text_seq("CORRESPONDING"):
    4904            by_name = True
    4905            if not side and not kind:
    4906                kind = "INNER"
    4907
    4908        on_column_list = None
    4909        if by_name and self._match_texts(("ON", "BY")):
    4910            on_column_list = self._parse_wrapped_csv(self._parse_column)
    4911
    4912        expression = self._parse_select(
    4913            nested=True, parse_set_operation=False, consume_pipe=consume_pipe
    4914        )
    4915
    4916        return self.expression(
    4917            operation,
    4918            comments=comments,
    4919            this=this,
    4920            distinct=distinct,
    4921            by_name=by_name,
    4922            expression=expression,
    4923            side=side,
    4924            kind=kind,
    4925            on=on_column_list,
    4926        )

def build_cast(self, strict: bool, **kwargs) -> sqlglot.expressions.Cast: View Source

    8865    def build_cast(self, strict: bool, **kwargs) -> exp.Cast:
    8866        exp_class = exp.Cast if strict else exp.TryCast
    8867
    8868        if exp_class == exp.TryCast:
    8869            kwargs["requires_string"] = self.dialect.TRY_CAST_REQUIRES_STRING
    8870
    8871        return self.expression(exp_class, **kwargs)

errors
sql