Edit on GitHub

# sqlglot.parser

View Source

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

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

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

###### Arguments:

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

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

    1553    def __init__(
    1554        self,
    1555        error_level: t.Optional[ErrorLevel] = None,
    1556        error_message_context: int = 100,
    1557        max_errors: int = 3,
    1558        dialect: DialectType = None,
    1559    ):
    1560        from sqlglot.dialects import Dialect
    1561
    1562        self.error_level = error_level or ErrorLevel.IMMEDIATE
    1563        self.error_message_context = error_message_context
    1564        self.max_errors = max_errors
    1565        self.dialect = Dialect.get_or_raise(dialect)
    1566        self.reset()

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

    1568    def reset(self):
    1569        self.sql = ""
    1570        self.errors = []
    1571        self._tokens = []
    1572        self._index = 0
    1573        self._curr = None
    1574        self._next = None
    1575        self._prev = None
    1576        self._prev_comments = None
    1577        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

    1579    def parse(
    1580        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
    1581    ) -> t.List[t.Optional[exp.Expression]]:
    1582        """
    1583        Parses a list of tokens and returns a list of syntax trees, one tree
    1584        per parsed SQL statement.
    1585
    1586        Args:
    1587            raw_tokens: The list of tokens.
    1588            sql: The original SQL string, used to produce helpful debug messages.
    1589
    1590        Returns:
    1591            The list of the produced syntax trees.
    1592        """
    1593        return self._parse(
    1594            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
    1595        )

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

    1597    def parse_into(
    1598        self,
    1599        expression_types: exp.IntoType,
    1600        raw_tokens: t.List[Token],
    1601        sql: t.Optional[str] = None,
    1602    ) -> t.List[t.Optional[exp.Expression]]:
    1603        """
    1604        Parses a list of tokens into a given Expression type. If a collection of Expression
    1605        types is given instead, this method will try to parse the token list into each one
    1606        of them, stopping at the first for which the parsing succeeds.
    1607
    1608        Args:
    1609            expression_types: The expression type(s) to try and parse the token list into.
    1610            raw_tokens: The list of tokens.
    1611            sql: The original SQL string, used to produce helpful debug messages.
    1612
    1613        Returns:
    1614            The target Expression.
    1615        """
    1616        errors = []
    1617        for expression_type in ensure_list(expression_types):
    1618            parser = self.EXPRESSION_PARSERS.get(expression_type)
    1619            if not parser:
    1620                raise TypeError(f"No parser registered for {expression_type}")
    1621
    1622            try:
    1623                return self._parse(parser, raw_tokens, sql)
    1624            except ParseError as e:
    1625                e.errors[0]["into_expression"] = expression_type
    1626                errors.append(e)
    1627
    1628        raise ParseError(
    1629            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
    1630            errors=merge_errors(errors),
    1631        ) 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

    1671    def check_errors(self) -> None:
    1672        """Logs or raises any found errors, depending on the chosen error level setting."""
    1673        if self.error_level == ErrorLevel.WARN:
    1674            for error in self.errors:
    1675                logger.error(str(error))
    1676        elif self.error_level == ErrorLevel.RAISE and self.errors:
    1677            raise ParseError(
    1678                concat_messages(self.errors, self.max_errors),
    1679                errors=merge_errors(self.errors),
    1680            )

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

    1682    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
    1683        """
    1684        Appends an error in the list of recorded errors or raises it, depending on the chosen
    1685        error level setting.
    1686        """
    1687        token = token or self._curr or self._prev or Token.string("")
    1688        start = token.start
    1689        end = token.end + 1
    1690        start_context = self.sql[max(start - self.error_message_context, 0) : start]
    1691        highlight = self.sql[start:end]
    1692        end_context = self.sql[end : end + self.error_message_context]
    1693
    1694        error = ParseError.new(
    1695            f"{message}. Line {token.line}, Col: {token.col}.\n"
    1696            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
    1697            description=message,
    1698            line=token.line,
    1699            col=token.col,
    1700            start_context=start_context,
    1701            highlight=highlight,
    1702            end_context=end_context,
    1703        )
    1704
    1705        if self.error_level == ErrorLevel.IMMEDIATE:
    1706            raise error
    1707
    1708        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

    1710    def expression(
    1711        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
    1712    ) -> E:
    1713        """
    1714        Creates a new, validated Expression.
    1715
    1716        Args:
    1717            exp_class: The expression class to instantiate.
    1718            comments: An optional list of comments to attach to the expression.
    1719            kwargs: The arguments to set for the expression along with their respective values.
    1720
    1721        Returns:
    1722            The target expression.
    1723        """
    1724        instance = exp_class(**kwargs)
    1725        instance.add_comments(comments) if comments else self._add_comments(instance)
    1726        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

    1733    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
    1734        """
    1735        Validates an Expression, making sure that all its mandatory arguments are set.
    1736
    1737        Args:
    1738            expression: The expression to validate.
    1739            args: An optional list of items that was used to instantiate the expression, if it's a Func.
    1740
    1741        Returns:
    1742            The validated expression.
    1743        """
    1744        if self.error_level != ErrorLevel.IGNORE:
    1745            for error_message in expression.error_messages(args):
    1746                self.raise_error(error_message)
    1747
    1748        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

    4759    def parse_set_operation(
    4760        self, this: t.Optional[exp.Expression], consume_pipe: bool = False
    4761    ) -> t.Optional[exp.Expression]:
    4762        start = self._index
    4763        _, side_token, kind_token = self._parse_join_parts()
    4764
    4765        side = side_token.text if side_token else None
    4766        kind = kind_token.text if kind_token else None
    4767
    4768        if not self._match_set(self.SET_OPERATIONS):
    4769            self._retreat(start)
    4770            return None
    4771
    4772        token_type = self._prev.token_type
    4773
    4774        if token_type == TokenType.UNION:
    4775            operation: t.Type[exp.SetOperation] = exp.Union
    4776        elif token_type == TokenType.EXCEPT:
    4777            operation = exp.Except
    4778        else:
    4779            operation = exp.Intersect
    4780
    4781        comments = self._prev.comments
    4782
    4783        if self._match(TokenType.DISTINCT):
    4784            distinct: t.Optional[bool] = True
    4785        elif self._match(TokenType.ALL):
    4786            distinct = False
    4787        else:
    4788            distinct = self.dialect.SET_OP_DISTINCT_BY_DEFAULT[operation]
    4789            if distinct is None:
    4790                self.raise_error(f"Expected DISTINCT or ALL for {operation.__name__}")
    4791
    4792        by_name = self._match_text_seq("BY", "NAME") or self._match_text_seq(
    4793            "STRICT", "CORRESPONDING"
    4794        )
    4795        if self._match_text_seq("CORRESPONDING"):
    4796            by_name = True
    4797            if not side and not kind:
    4798                kind = "INNER"
    4799
    4800        on_column_list = None
    4801        if by_name and self._match_texts(("ON", "BY")):
    4802            on_column_list = self._parse_wrapped_csv(self._parse_column)
    4803
    4804        expression = self._parse_select(
    4805            nested=True, parse_set_operation=False, consume_pipe=consume_pipe
    4806        )
    4807
    4808        return self.expression(
    4809            operation,
    4810            comments=comments,
    4811            this=this,
    4812            distinct=distinct,
    4813            by_name=by_name,
    4814            expression=expression,
    4815            side=side,
    4816            kind=kind,
    4817            on=on_column_list,
    4818        )

errors
sql