Edit on GitHub

sqlglot.parser

   1from __future__ import annotations
   2
   3import logging
   4import typing as t
   5from collections import defaultdict
   6
   7from sqlglot import exp
   8from sqlglot.errors import ErrorLevel, ParseError, concat_messages, merge_errors
   9from sqlglot.helper import apply_index_offset, ensure_list, seq_get
  10from sqlglot.time import format_time
  11from sqlglot.tokens import Token, Tokenizer, TokenType
  12from sqlglot.trie import TrieResult, in_trie, new_trie
  13
  14if t.TYPE_CHECKING:
  15    from sqlglot._typing import E, Lit
  16    from sqlglot.dialects.dialect import Dialect, DialectType
  17
  18    T = t.TypeVar("T")
  19
  20logger = logging.getLogger("sqlglot")
  21
  22OPTIONS_TYPE = t.Dict[str, t.Sequence[t.Union[t.Sequence[str], str]]]
  23
  24
  25def build_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
  26    if len(args) == 1 and args[0].is_star:
  27        return exp.StarMap(this=args[0])
  28
  29    keys = []
  30    values = []
  31    for i in range(0, len(args), 2):
  32        keys.append(args[i])
  33        values.append(args[i + 1])
  34
  35    return exp.VarMap(keys=exp.array(*keys, copy=False), values=exp.array(*values, copy=False))
  36
  37
  38def build_like(args: t.List) -> exp.Escape | exp.Like:
  39    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
  40    return exp.Escape(this=like, expression=seq_get(args, 2)) if len(args) > 2 else like
  41
  42
  43def binary_range_parser(
  44    expr_type: t.Type[exp.Expression], reverse_args: bool = False
  45) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
  46    def _parse_binary_range(
  47        self: Parser, this: t.Optional[exp.Expression]
  48    ) -> t.Optional[exp.Expression]:
  49        expression = self._parse_bitwise()
  50        if reverse_args:
  51            this, expression = expression, this
  52        return self._parse_escape(self.expression(expr_type, this=this, expression=expression))
  53
  54    return _parse_binary_range
  55
  56
  57def build_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
  58    # Default argument order is base, expression
  59    this = seq_get(args, 0)
  60    expression = seq_get(args, 1)
  61
  62    if expression:
  63        if not dialect.LOG_BASE_FIRST:
  64            this, expression = expression, this
  65        return exp.Log(this=this, expression=expression)
  66
  67    return (exp.Ln if dialect.parser_class.LOG_DEFAULTS_TO_LN else exp.Log)(this=this)
  68
  69
  70def build_hex(args: t.List, dialect: Dialect) -> exp.Hex | exp.LowerHex:
  71    arg = seq_get(args, 0)
  72    return exp.LowerHex(this=arg) if dialect.HEX_LOWERCASE else exp.Hex(this=arg)
  73
  74
  75def build_lower(args: t.List) -> exp.Lower | exp.Hex:
  76    # LOWER(HEX(..)) can be simplified to LowerHex to simplify its transpilation
  77    arg = seq_get(args, 0)
  78    return exp.LowerHex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Lower(this=arg)
  79
  80
  81def build_upper(args: t.List) -> exp.Upper | exp.Hex:
  82    # UPPER(HEX(..)) can be simplified to Hex to simplify its transpilation
  83    arg = seq_get(args, 0)
  84    return exp.Hex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Upper(this=arg)
  85
  86
  87def build_extract_json_with_path(expr_type: t.Type[E]) -> t.Callable[[t.List, Dialect], E]:
  88    def _builder(args: t.List, dialect: Dialect) -> E:
  89        expression = expr_type(
  90            this=seq_get(args, 0), expression=dialect.to_json_path(seq_get(args, 1))
  91        )
  92        if len(args) > 2 and expr_type is exp.JSONExtract:
  93            expression.set("expressions", args[2:])
  94
  95        return expression
  96
  97    return _builder
  98
  99
 100def build_mod(args: t.List) -> exp.Mod:
 101    this = seq_get(args, 0)
 102    expression = seq_get(args, 1)
 103
 104    # Wrap the operands if they are binary nodes, e.g. MOD(a + 1, 7) -> (a + 1) % 7
 105    this = exp.Paren(this=this) if isinstance(this, exp.Binary) else this
 106    expression = exp.Paren(this=expression) if isinstance(expression, exp.Binary) else expression
 107
 108    return exp.Mod(this=this, expression=expression)
 109
 110
 111def build_pad(args: t.List, is_left: bool = True):
 112    return exp.Pad(
 113        this=seq_get(args, 0),
 114        expression=seq_get(args, 1),
 115        fill_pattern=seq_get(args, 2),
 116        is_left=is_left,
 117    )
 118
 119
 120def build_array_constructor(
 121    exp_class: t.Type[E], args: t.List, bracket_kind: TokenType, dialect: Dialect
 122) -> exp.Expression:
 123    array_exp = exp_class(expressions=args)
 124
 125    if exp_class == exp.Array and dialect.HAS_DISTINCT_ARRAY_CONSTRUCTORS:
 126        array_exp.set("bracket_notation", bracket_kind == TokenType.L_BRACKET)
 127
 128    return array_exp
 129
 130
 131def build_convert_timezone(
 132    args: t.List, default_source_tz: t.Optional[str] = None
 133) -> t.Union[exp.ConvertTimezone, exp.Anonymous]:
 134    if len(args) == 2:
 135        source_tz = exp.Literal.string(default_source_tz) if default_source_tz else None
 136        return exp.ConvertTimezone(
 137            source_tz=source_tz, target_tz=seq_get(args, 0), timestamp=seq_get(args, 1)
 138        )
 139
 140    return exp.ConvertTimezone.from_arg_list(args)
 141
 142
 143def build_trim(args: t.List, is_left: bool = True):
 144    return exp.Trim(
 145        this=seq_get(args, 0),
 146        expression=seq_get(args, 1),
 147        position="LEADING" if is_left else "TRAILING",
 148    )
 149
 150
 151def build_coalesce(args: t.List, is_nvl: t.Optional[bool] = None) -> exp.Coalesce:
 152    return exp.Coalesce(this=seq_get(args, 0), expressions=args[1:], is_nvl=is_nvl)
 153
 154
 155class _Parser(type):
 156    def __new__(cls, clsname, bases, attrs):
 157        klass = super().__new__(cls, clsname, bases, attrs)
 158
 159        klass.SHOW_TRIE = new_trie(key.split(" ") for key in klass.SHOW_PARSERS)
 160        klass.SET_TRIE = new_trie(key.split(" ") for key in klass.SET_PARSERS)
 161
 162        return klass
 163
 164
 165class Parser(metaclass=_Parser):
 166    """
 167    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
 168
 169    Args:
 170        error_level: The desired error level.
 171            Default: ErrorLevel.IMMEDIATE
 172        error_message_context: The amount of context to capture from a query string when displaying
 173            the error message (in number of characters).
 174            Default: 100
 175        max_errors: Maximum number of error messages to include in a raised ParseError.
 176            This is only relevant if error_level is ErrorLevel.RAISE.
 177            Default: 3
 178    """
 179
 180    FUNCTIONS: t.Dict[str, t.Callable] = {
 181        **{name: func.from_arg_list for name, func in exp.FUNCTION_BY_NAME.items()},
 182        **dict.fromkeys(("COALESCE", "IFNULL", "NVL"), build_coalesce),
 183        "ARRAY": lambda args, dialect: exp.Array(expressions=args),
 184        "ARRAYAGG": lambda args, dialect: exp.ArrayAgg(
 185            this=seq_get(args, 0), nulls_excluded=dialect.ARRAY_AGG_INCLUDES_NULLS is None or None
 186        ),
 187        "ARRAY_AGG": lambda args, dialect: exp.ArrayAgg(
 188            this=seq_get(args, 0), nulls_excluded=dialect.ARRAY_AGG_INCLUDES_NULLS is None or None
 189        ),
 190        "CHAR": lambda args: exp.Chr(expressions=args),
 191        "CHR": lambda args: exp.Chr(expressions=args),
 192        "COUNT": lambda args: exp.Count(this=seq_get(args, 0), expressions=args[1:], big_int=True),
 193        "CONCAT": lambda args, dialect: exp.Concat(
 194            expressions=args,
 195            safe=not dialect.STRICT_STRING_CONCAT,
 196            coalesce=dialect.CONCAT_COALESCE,
 197        ),
 198        "CONCAT_WS": lambda args, dialect: exp.ConcatWs(
 199            expressions=args,
 200            safe=not dialect.STRICT_STRING_CONCAT,
 201            coalesce=dialect.CONCAT_COALESCE,
 202        ),
 203        "CONVERT_TIMEZONE": build_convert_timezone,
 204        "DATE_TO_DATE_STR": lambda args: exp.Cast(
 205            this=seq_get(args, 0),
 206            to=exp.DataType(this=exp.DataType.Type.TEXT),
 207        ),
 208        "GENERATE_DATE_ARRAY": lambda args: exp.GenerateDateArray(
 209            start=seq_get(args, 0),
 210            end=seq_get(args, 1),
 211            step=seq_get(args, 2) or exp.Interval(this=exp.Literal.number(1), unit=exp.var("DAY")),
 212        ),
 213        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
 214        "HEX": build_hex,
 215        "INSTR": lambda args: exp.StrPosition(this=seq_get(args, 0), substr=seq_get(args, 1)),
 216        "JSON_EXTRACT": build_extract_json_with_path(exp.JSONExtract),
 217        "JSON_EXTRACT_SCALAR": build_extract_json_with_path(exp.JSONExtractScalar),
 218        "JSON_EXTRACT_PATH_TEXT": build_extract_json_with_path(exp.JSONExtractScalar),
 219        "LIKE": build_like,
 220        "LOG": build_logarithm,
 221        "LOG2": lambda args: exp.Log(this=exp.Literal.number(2), expression=seq_get(args, 0)),
 222        "LOG10": lambda args: exp.Log(this=exp.Literal.number(10), expression=seq_get(args, 0)),
 223        "LOWER": build_lower,
 224        "LPAD": lambda args: build_pad(args),
 225        "LEFTPAD": lambda args: build_pad(args),
 226        "LTRIM": lambda args: build_trim(args),
 227        "MOD": build_mod,
 228        "RIGHTPAD": lambda args: build_pad(args, is_left=False),
 229        "RPAD": lambda args: build_pad(args, is_left=False),
 230        "RTRIM": lambda args: build_trim(args, is_left=False),
 231        "SCOPE_RESOLUTION": lambda args: exp.ScopeResolution(expression=seq_get(args, 0))
 232        if len(args) != 2
 233        else exp.ScopeResolution(this=seq_get(args, 0), expression=seq_get(args, 1)),
 234        "TIME_TO_TIME_STR": lambda args: exp.Cast(
 235            this=seq_get(args, 0),
 236            to=exp.DataType(this=exp.DataType.Type.TEXT),
 237        ),
 238        "TO_HEX": build_hex,
 239        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
 240            this=exp.Cast(
 241                this=seq_get(args, 0),
 242                to=exp.DataType(this=exp.DataType.Type.TEXT),
 243            ),
 244            start=exp.Literal.number(1),
 245            length=exp.Literal.number(10),
 246        ),
 247        "UNNEST": lambda args: exp.Unnest(expressions=ensure_list(seq_get(args, 0))),
 248        "UPPER": build_upper,
 249        "VAR_MAP": build_var_map,
 250    }
 251
 252    NO_PAREN_FUNCTIONS = {
 253        TokenType.CURRENT_DATE: exp.CurrentDate,
 254        TokenType.CURRENT_DATETIME: exp.CurrentDate,
 255        TokenType.CURRENT_TIME: exp.CurrentTime,
 256        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
 257        TokenType.CURRENT_USER: exp.CurrentUser,
 258    }
 259
 260    STRUCT_TYPE_TOKENS = {
 261        TokenType.NESTED,
 262        TokenType.OBJECT,
 263        TokenType.STRUCT,
 264        TokenType.UNION,
 265    }
 266
 267    NESTED_TYPE_TOKENS = {
 268        TokenType.ARRAY,
 269        TokenType.LIST,
 270        TokenType.LOWCARDINALITY,
 271        TokenType.MAP,
 272        TokenType.NULLABLE,
 273        TokenType.RANGE,
 274        *STRUCT_TYPE_TOKENS,
 275    }
 276
 277    ENUM_TYPE_TOKENS = {
 278        TokenType.ENUM,
 279        TokenType.ENUM8,
 280        TokenType.ENUM16,
 281    }
 282
 283    AGGREGATE_TYPE_TOKENS = {
 284        TokenType.AGGREGATEFUNCTION,
 285        TokenType.SIMPLEAGGREGATEFUNCTION,
 286    }
 287
 288    TYPE_TOKENS = {
 289        TokenType.BIT,
 290        TokenType.BOOLEAN,
 291        TokenType.TINYINT,
 292        TokenType.UTINYINT,
 293        TokenType.SMALLINT,
 294        TokenType.USMALLINT,
 295        TokenType.INT,
 296        TokenType.UINT,
 297        TokenType.BIGINT,
 298        TokenType.UBIGINT,
 299        TokenType.INT128,
 300        TokenType.UINT128,
 301        TokenType.INT256,
 302        TokenType.UINT256,
 303        TokenType.MEDIUMINT,
 304        TokenType.UMEDIUMINT,
 305        TokenType.FIXEDSTRING,
 306        TokenType.FLOAT,
 307        TokenType.DOUBLE,
 308        TokenType.CHAR,
 309        TokenType.NCHAR,
 310        TokenType.VARCHAR,
 311        TokenType.NVARCHAR,
 312        TokenType.BPCHAR,
 313        TokenType.TEXT,
 314        TokenType.MEDIUMTEXT,
 315        TokenType.LONGTEXT,
 316        TokenType.MEDIUMBLOB,
 317        TokenType.LONGBLOB,
 318        TokenType.BINARY,
 319        TokenType.VARBINARY,
 320        TokenType.JSON,
 321        TokenType.JSONB,
 322        TokenType.INTERVAL,
 323        TokenType.TINYBLOB,
 324        TokenType.TINYTEXT,
 325        TokenType.TIME,
 326        TokenType.TIMETZ,
 327        TokenType.TIMESTAMP,
 328        TokenType.TIMESTAMP_S,
 329        TokenType.TIMESTAMP_MS,
 330        TokenType.TIMESTAMP_NS,
 331        TokenType.TIMESTAMPTZ,
 332        TokenType.TIMESTAMPLTZ,
 333        TokenType.TIMESTAMPNTZ,
 334        TokenType.DATETIME,
 335        TokenType.DATETIME64,
 336        TokenType.DATE,
 337        TokenType.DATE32,
 338        TokenType.INT4RANGE,
 339        TokenType.INT4MULTIRANGE,
 340        TokenType.INT8RANGE,
 341        TokenType.INT8MULTIRANGE,
 342        TokenType.NUMRANGE,
 343        TokenType.NUMMULTIRANGE,
 344        TokenType.TSRANGE,
 345        TokenType.TSMULTIRANGE,
 346        TokenType.TSTZRANGE,
 347        TokenType.TSTZMULTIRANGE,
 348        TokenType.DATERANGE,
 349        TokenType.DATEMULTIRANGE,
 350        TokenType.DECIMAL,
 351        TokenType.DECIMAL32,
 352        TokenType.DECIMAL64,
 353        TokenType.DECIMAL128,
 354        TokenType.DECIMAL256,
 355        TokenType.UDECIMAL,
 356        TokenType.BIGDECIMAL,
 357        TokenType.UUID,
 358        TokenType.GEOGRAPHY,
 359        TokenType.GEOMETRY,
 360        TokenType.POINT,
 361        TokenType.RING,
 362        TokenType.LINESTRING,
 363        TokenType.MULTILINESTRING,
 364        TokenType.POLYGON,
 365        TokenType.MULTIPOLYGON,
 366        TokenType.HLLSKETCH,
 367        TokenType.HSTORE,
 368        TokenType.PSEUDO_TYPE,
 369        TokenType.SUPER,
 370        TokenType.SERIAL,
 371        TokenType.SMALLSERIAL,
 372        TokenType.BIGSERIAL,
 373        TokenType.XML,
 374        TokenType.YEAR,
 375        TokenType.UNIQUEIDENTIFIER,
 376        TokenType.USERDEFINED,
 377        TokenType.MONEY,
 378        TokenType.SMALLMONEY,
 379        TokenType.ROWVERSION,
 380        TokenType.IMAGE,
 381        TokenType.VARIANT,
 382        TokenType.VECTOR,
 383        TokenType.OBJECT,
 384        TokenType.OBJECT_IDENTIFIER,
 385        TokenType.INET,
 386        TokenType.IPADDRESS,
 387        TokenType.IPPREFIX,
 388        TokenType.IPV4,
 389        TokenType.IPV6,
 390        TokenType.UNKNOWN,
 391        TokenType.NULL,
 392        TokenType.NAME,
 393        TokenType.TDIGEST,
 394        *ENUM_TYPE_TOKENS,
 395        *NESTED_TYPE_TOKENS,
 396        *AGGREGATE_TYPE_TOKENS,
 397    }
 398
 399    SIGNED_TO_UNSIGNED_TYPE_TOKEN = {
 400        TokenType.BIGINT: TokenType.UBIGINT,
 401        TokenType.INT: TokenType.UINT,
 402        TokenType.MEDIUMINT: TokenType.UMEDIUMINT,
 403        TokenType.SMALLINT: TokenType.USMALLINT,
 404        TokenType.TINYINT: TokenType.UTINYINT,
 405        TokenType.DECIMAL: TokenType.UDECIMAL,
 406    }
 407
 408    SUBQUERY_PREDICATES = {
 409        TokenType.ANY: exp.Any,
 410        TokenType.ALL: exp.All,
 411        TokenType.EXISTS: exp.Exists,
 412        TokenType.SOME: exp.Any,
 413    }
 414
 415    RESERVED_TOKENS = {
 416        *Tokenizer.SINGLE_TOKENS.values(),
 417        TokenType.SELECT,
 418    } - {TokenType.IDENTIFIER}
 419
 420    DB_CREATABLES = {
 421        TokenType.DATABASE,
 422        TokenType.DICTIONARY,
 423        TokenType.MODEL,
 424        TokenType.SCHEMA,
 425        TokenType.SEQUENCE,
 426        TokenType.STORAGE_INTEGRATION,
 427        TokenType.TABLE,
 428        TokenType.TAG,
 429        TokenType.VIEW,
 430        TokenType.WAREHOUSE,
 431        TokenType.STREAMLIT,
 432    }
 433
 434    CREATABLES = {
 435        TokenType.COLUMN,
 436        TokenType.CONSTRAINT,
 437        TokenType.FOREIGN_KEY,
 438        TokenType.FUNCTION,
 439        TokenType.INDEX,
 440        TokenType.PROCEDURE,
 441        *DB_CREATABLES,
 442    }
 443
 444    ALTERABLES = {
 445        TokenType.INDEX,
 446        TokenType.TABLE,
 447        TokenType.VIEW,
 448    }
 449
 450    # Tokens that can represent identifiers
 451    ID_VAR_TOKENS = {
 452        TokenType.ALL,
 453        TokenType.VAR,
 454        TokenType.ANTI,
 455        TokenType.APPLY,
 456        TokenType.ASC,
 457        TokenType.ASOF,
 458        TokenType.AUTO_INCREMENT,
 459        TokenType.BEGIN,
 460        TokenType.BPCHAR,
 461        TokenType.CACHE,
 462        TokenType.CASE,
 463        TokenType.COLLATE,
 464        TokenType.COMMAND,
 465        TokenType.COMMENT,
 466        TokenType.COMMIT,
 467        TokenType.CONSTRAINT,
 468        TokenType.COPY,
 469        TokenType.CUBE,
 470        TokenType.DEFAULT,
 471        TokenType.DELETE,
 472        TokenType.DESC,
 473        TokenType.DESCRIBE,
 474        TokenType.DICTIONARY,
 475        TokenType.DIV,
 476        TokenType.END,
 477        TokenType.EXECUTE,
 478        TokenType.ESCAPE,
 479        TokenType.FALSE,
 480        TokenType.FIRST,
 481        TokenType.FILTER,
 482        TokenType.FINAL,
 483        TokenType.FORMAT,
 484        TokenType.FULL,
 485        TokenType.IDENTIFIER,
 486        TokenType.IS,
 487        TokenType.ISNULL,
 488        TokenType.INTERVAL,
 489        TokenType.KEEP,
 490        TokenType.KILL,
 491        TokenType.LEFT,
 492        TokenType.LOAD,
 493        TokenType.MERGE,
 494        TokenType.NATURAL,
 495        TokenType.NEXT,
 496        TokenType.OFFSET,
 497        TokenType.OPERATOR,
 498        TokenType.ORDINALITY,
 499        TokenType.OVERLAPS,
 500        TokenType.OVERWRITE,
 501        TokenType.PARTITION,
 502        TokenType.PERCENT,
 503        TokenType.PIVOT,
 504        TokenType.PRAGMA,
 505        TokenType.RANGE,
 506        TokenType.RECURSIVE,
 507        TokenType.REFERENCES,
 508        TokenType.REFRESH,
 509        TokenType.RENAME,
 510        TokenType.REPLACE,
 511        TokenType.RIGHT,
 512        TokenType.ROLLUP,
 513        TokenType.ROW,
 514        TokenType.ROWS,
 515        TokenType.SEMI,
 516        TokenType.SET,
 517        TokenType.SETTINGS,
 518        TokenType.SHOW,
 519        TokenType.TEMPORARY,
 520        TokenType.TOP,
 521        TokenType.TRUE,
 522        TokenType.TRUNCATE,
 523        TokenType.UNIQUE,
 524        TokenType.UNNEST,
 525        TokenType.UNPIVOT,
 526        TokenType.UPDATE,
 527        TokenType.USE,
 528        TokenType.VOLATILE,
 529        TokenType.WINDOW,
 530        *CREATABLES,
 531        *SUBQUERY_PREDICATES,
 532        *TYPE_TOKENS,
 533        *NO_PAREN_FUNCTIONS,
 534    }
 535    ID_VAR_TOKENS.remove(TokenType.UNION)
 536
 537    INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
 538
 539    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
 540        TokenType.ANTI,
 541        TokenType.APPLY,
 542        TokenType.ASOF,
 543        TokenType.FULL,
 544        TokenType.LEFT,
 545        TokenType.LOCK,
 546        TokenType.NATURAL,
 547        TokenType.OFFSET,
 548        TokenType.RIGHT,
 549        TokenType.SEMI,
 550        TokenType.WINDOW,
 551    }
 552
 553    ALIAS_TOKENS = ID_VAR_TOKENS
 554
 555    ARRAY_CONSTRUCTORS = {
 556        "ARRAY": exp.Array,
 557        "LIST": exp.List,
 558    }
 559
 560    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
 561
 562    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
 563
 564    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
 565
 566    FUNC_TOKENS = {
 567        TokenType.COLLATE,
 568        TokenType.COMMAND,
 569        TokenType.CURRENT_DATE,
 570        TokenType.CURRENT_DATETIME,
 571        TokenType.CURRENT_TIMESTAMP,
 572        TokenType.CURRENT_TIME,
 573        TokenType.CURRENT_USER,
 574        TokenType.FILTER,
 575        TokenType.FIRST,
 576        TokenType.FORMAT,
 577        TokenType.GLOB,
 578        TokenType.IDENTIFIER,
 579        TokenType.INDEX,
 580        TokenType.ISNULL,
 581        TokenType.ILIKE,
 582        TokenType.INSERT,
 583        TokenType.LIKE,
 584        TokenType.MERGE,
 585        TokenType.OFFSET,
 586        TokenType.PRIMARY_KEY,
 587        TokenType.RANGE,
 588        TokenType.REPLACE,
 589        TokenType.RLIKE,
 590        TokenType.ROW,
 591        TokenType.UNNEST,
 592        TokenType.VAR,
 593        TokenType.LEFT,
 594        TokenType.RIGHT,
 595        TokenType.SEQUENCE,
 596        TokenType.DATE,
 597        TokenType.DATETIME,
 598        TokenType.TABLE,
 599        TokenType.TIMESTAMP,
 600        TokenType.TIMESTAMPTZ,
 601        TokenType.TRUNCATE,
 602        TokenType.WINDOW,
 603        TokenType.XOR,
 604        *TYPE_TOKENS,
 605        *SUBQUERY_PREDICATES,
 606    }
 607
 608    CONJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
 609        TokenType.AND: exp.And,
 610    }
 611
 612    ASSIGNMENT: t.Dict[TokenType, t.Type[exp.Expression]] = {
 613        TokenType.COLON_EQ: exp.PropertyEQ,
 614    }
 615
 616    DISJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
 617        TokenType.OR: exp.Or,
 618    }
 619
 620    EQUALITY = {
 621        TokenType.EQ: exp.EQ,
 622        TokenType.NEQ: exp.NEQ,
 623        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
 624    }
 625
 626    COMPARISON = {
 627        TokenType.GT: exp.GT,
 628        TokenType.GTE: exp.GTE,
 629        TokenType.LT: exp.LT,
 630        TokenType.LTE: exp.LTE,
 631    }
 632
 633    BITWISE = {
 634        TokenType.AMP: exp.BitwiseAnd,
 635        TokenType.CARET: exp.BitwiseXor,
 636        TokenType.PIPE: exp.BitwiseOr,
 637    }
 638
 639    TERM = {
 640        TokenType.DASH: exp.Sub,
 641        TokenType.PLUS: exp.Add,
 642        TokenType.MOD: exp.Mod,
 643        TokenType.COLLATE: exp.Collate,
 644    }
 645
 646    FACTOR = {
 647        TokenType.DIV: exp.IntDiv,
 648        TokenType.LR_ARROW: exp.Distance,
 649        TokenType.SLASH: exp.Div,
 650        TokenType.STAR: exp.Mul,
 651    }
 652
 653    EXPONENT: t.Dict[TokenType, t.Type[exp.Expression]] = {}
 654
 655    TIMES = {
 656        TokenType.TIME,
 657        TokenType.TIMETZ,
 658    }
 659
 660    TIMESTAMPS = {
 661        TokenType.TIMESTAMP,
 662        TokenType.TIMESTAMPTZ,
 663        TokenType.TIMESTAMPLTZ,
 664        *TIMES,
 665    }
 666
 667    SET_OPERATIONS = {
 668        TokenType.UNION,
 669        TokenType.INTERSECT,
 670        TokenType.EXCEPT,
 671    }
 672
 673    JOIN_METHODS = {
 674        TokenType.ASOF,
 675        TokenType.NATURAL,
 676        TokenType.POSITIONAL,
 677    }
 678
 679    JOIN_SIDES = {
 680        TokenType.LEFT,
 681        TokenType.RIGHT,
 682        TokenType.FULL,
 683    }
 684
 685    JOIN_KINDS = {
 686        TokenType.ANTI,
 687        TokenType.CROSS,
 688        TokenType.INNER,
 689        TokenType.OUTER,
 690        TokenType.SEMI,
 691        TokenType.STRAIGHT_JOIN,
 692    }
 693
 694    JOIN_HINTS: t.Set[str] = set()
 695
 696    LAMBDAS = {
 697        TokenType.ARROW: lambda self, expressions: self.expression(
 698            exp.Lambda,
 699            this=self._replace_lambda(
 700                self._parse_assignment(),
 701                expressions,
 702            ),
 703            expressions=expressions,
 704        ),
 705        TokenType.FARROW: lambda self, expressions: self.expression(
 706            exp.Kwarg,
 707            this=exp.var(expressions[0].name),
 708            expression=self._parse_assignment(),
 709        ),
 710    }
 711
 712    COLUMN_OPERATORS = {
 713        TokenType.DOT: None,
 714        TokenType.DCOLON: lambda self, this, to: self.expression(
 715            exp.Cast if self.STRICT_CAST else exp.TryCast,
 716            this=this,
 717            to=to,
 718        ),
 719        TokenType.ARROW: lambda self, this, path: self.expression(
 720            exp.JSONExtract,
 721            this=this,
 722            expression=self.dialect.to_json_path(path),
 723            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
 724        ),
 725        TokenType.DARROW: lambda self, this, path: self.expression(
 726            exp.JSONExtractScalar,
 727            this=this,
 728            expression=self.dialect.to_json_path(path),
 729            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
 730        ),
 731        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
 732            exp.JSONBExtract,
 733            this=this,
 734            expression=path,
 735        ),
 736        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
 737            exp.JSONBExtractScalar,
 738            this=this,
 739            expression=path,
 740        ),
 741        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
 742            exp.JSONBContains,
 743            this=this,
 744            expression=key,
 745        ),
 746    }
 747
 748    EXPRESSION_PARSERS = {
 749        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
 750        exp.Column: lambda self: self._parse_column(),
 751        exp.Condition: lambda self: self._parse_assignment(),
 752        exp.DataType: lambda self: self._parse_types(allow_identifiers=False, schema=True),
 753        exp.Expression: lambda self: self._parse_expression(),
 754        exp.From: lambda self: self._parse_from(joins=True),
 755        exp.Group: lambda self: self._parse_group(),
 756        exp.Having: lambda self: self._parse_having(),
 757        exp.Identifier: lambda self: self._parse_id_var(),
 758        exp.Join: lambda self: self._parse_join(),
 759        exp.Lambda: lambda self: self._parse_lambda(),
 760        exp.Lateral: lambda self: self._parse_lateral(),
 761        exp.Limit: lambda self: self._parse_limit(),
 762        exp.Offset: lambda self: self._parse_offset(),
 763        exp.Order: lambda self: self._parse_order(),
 764        exp.Ordered: lambda self: self._parse_ordered(),
 765        exp.Properties: lambda self: self._parse_properties(),
 766        exp.Qualify: lambda self: self._parse_qualify(),
 767        exp.Returning: lambda self: self._parse_returning(),
 768        exp.Select: lambda self: self._parse_select(),
 769        exp.Sort: lambda self: self._parse_sort(exp.Sort, TokenType.SORT_BY),
 770        exp.Table: lambda self: self._parse_table_parts(),
 771        exp.TableAlias: lambda self: self._parse_table_alias(),
 772        exp.When: lambda self: seq_get(self._parse_when_matched(), 0),
 773        exp.Where: lambda self: self._parse_where(),
 774        exp.Window: lambda self: self._parse_named_window(),
 775        exp.With: lambda self: self._parse_with(),
 776        "JOIN_TYPE": lambda self: self._parse_join_parts(),
 777    }
 778
 779    STATEMENT_PARSERS = {
 780        TokenType.ALTER: lambda self: self._parse_alter(),
 781        TokenType.BEGIN: lambda self: self._parse_transaction(),
 782        TokenType.CACHE: lambda self: self._parse_cache(),
 783        TokenType.COMMENT: lambda self: self._parse_comment(),
 784        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
 785        TokenType.COPY: lambda self: self._parse_copy(),
 786        TokenType.CREATE: lambda self: self._parse_create(),
 787        TokenType.DELETE: lambda self: self._parse_delete(),
 788        TokenType.DESC: lambda self: self._parse_describe(),
 789        TokenType.DESCRIBE: lambda self: self._parse_describe(),
 790        TokenType.DROP: lambda self: self._parse_drop(),
 791        TokenType.GRANT: lambda self: self._parse_grant(),
 792        TokenType.INSERT: lambda self: self._parse_insert(),
 793        TokenType.KILL: lambda self: self._parse_kill(),
 794        TokenType.LOAD: lambda self: self._parse_load(),
 795        TokenType.MERGE: lambda self: self._parse_merge(),
 796        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
 797        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
 798        TokenType.REFRESH: lambda self: self._parse_refresh(),
 799        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
 800        TokenType.SET: lambda self: self._parse_set(),
 801        TokenType.TRUNCATE: lambda self: self._parse_truncate_table(),
 802        TokenType.UNCACHE: lambda self: self._parse_uncache(),
 803        TokenType.UPDATE: lambda self: self._parse_update(),
 804        TokenType.USE: lambda self: self.expression(
 805            exp.Use,
 806            kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
 807            this=self._parse_table(schema=False),
 808        ),
 809        TokenType.SEMICOLON: lambda self: self.expression(exp.Semicolon),
 810    }
 811
 812    UNARY_PARSERS = {
 813        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
 814        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
 815        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
 816        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
 817        TokenType.PIPE_SLASH: lambda self: self.expression(exp.Sqrt, this=self._parse_unary()),
 818        TokenType.DPIPE_SLASH: lambda self: self.expression(exp.Cbrt, this=self._parse_unary()),
 819    }
 820
 821    STRING_PARSERS = {
 822        TokenType.HEREDOC_STRING: lambda self, token: self.expression(
 823            exp.RawString, this=token.text
 824        ),
 825        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
 826            exp.National, this=token.text
 827        ),
 828        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
 829        TokenType.STRING: lambda self, token: self.expression(
 830            exp.Literal, this=token.text, is_string=True
 831        ),
 832        TokenType.UNICODE_STRING: lambda self, token: self.expression(
 833            exp.UnicodeString,
 834            this=token.text,
 835            escape=self._match_text_seq("UESCAPE") and self._parse_string(),
 836        ),
 837    }
 838
 839    NUMERIC_PARSERS = {
 840        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
 841        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
 842        TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text),
 843        TokenType.NUMBER: lambda self, token: self.expression(
 844            exp.Literal, this=token.text, is_string=False
 845        ),
 846    }
 847
 848    PRIMARY_PARSERS = {
 849        **STRING_PARSERS,
 850        **NUMERIC_PARSERS,
 851        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
 852        TokenType.NULL: lambda self, _: self.expression(exp.Null),
 853        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
 854        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
 855        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
 856        TokenType.STAR: lambda self, _: self._parse_star_ops(),
 857    }
 858
 859    PLACEHOLDER_PARSERS = {
 860        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
 861        TokenType.PARAMETER: lambda self: self._parse_parameter(),
 862        TokenType.COLON: lambda self: (
 863            self.expression(exp.Placeholder, this=self._prev.text)
 864            if self._match_set(self.ID_VAR_TOKENS)
 865            else None
 866        ),
 867    }
 868
 869    RANGE_PARSERS = {
 870        TokenType.AT_GT: binary_range_parser(exp.ArrayContainsAll),
 871        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
 872        TokenType.GLOB: binary_range_parser(exp.Glob),
 873        TokenType.ILIKE: binary_range_parser(exp.ILike),
 874        TokenType.IN: lambda self, this: self._parse_in(this),
 875        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
 876        TokenType.IS: lambda self, this: self._parse_is(this),
 877        TokenType.LIKE: binary_range_parser(exp.Like),
 878        TokenType.LT_AT: binary_range_parser(exp.ArrayContainsAll, reverse_args=True),
 879        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
 880        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
 881        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
 882        TokenType.FOR: lambda self, this: self._parse_comprehension(this),
 883    }
 884
 885    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
 886        "ALLOWED_VALUES": lambda self: self.expression(
 887            exp.AllowedValuesProperty, expressions=self._parse_csv(self._parse_primary)
 888        ),
 889        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
 890        "AUTO": lambda self: self._parse_auto_property(),
 891        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
 892        "BACKUP": lambda self: self.expression(
 893            exp.BackupProperty, this=self._parse_var(any_token=True)
 894        ),
 895        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
 896        "CHARSET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 897        "CHARACTER SET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 898        "CHECKSUM": lambda self: self._parse_checksum(),
 899        "CLUSTER BY": lambda self: self._parse_cluster(),
 900        "CLUSTERED": lambda self: self._parse_clustered_by(),
 901        "COLLATE": lambda self, **kwargs: self._parse_property_assignment(
 902            exp.CollateProperty, **kwargs
 903        ),
 904        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
 905        "CONTAINS": lambda self: self._parse_contains_property(),
 906        "COPY": lambda self: self._parse_copy_property(),
 907        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
 908        "DATA_DELETION": lambda self: self._parse_data_deletion_property(),
 909        "DEFINER": lambda self: self._parse_definer(),
 910        "DETERMINISTIC": lambda self: self.expression(
 911            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 912        ),
 913        "DISTRIBUTED": lambda self: self._parse_distributed_property(),
 914        "DUPLICATE": lambda self: self._parse_duplicate(),
 915        "DYNAMIC": lambda self: self.expression(exp.DynamicProperty),
 916        "DISTKEY": lambda self: self._parse_distkey(),
 917        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
 918        "EMPTY": lambda self: self.expression(exp.EmptyProperty),
 919        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
 920        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
 921        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
 922        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
 923        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 924        "FREESPACE": lambda self: self._parse_freespace(),
 925        "GLOBAL": lambda self: self.expression(exp.GlobalProperty),
 926        "HEAP": lambda self: self.expression(exp.HeapProperty),
 927        "ICEBERG": lambda self: self.expression(exp.IcebergProperty),
 928        "IMMUTABLE": lambda self: self.expression(
 929            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 930        ),
 931        "INHERITS": lambda self: self.expression(
 932            exp.InheritsProperty, expressions=self._parse_wrapped_csv(self._parse_table)
 933        ),
 934        "INPUT": lambda self: self.expression(exp.InputModelProperty, this=self._parse_schema()),
 935        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
 936        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
 937        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
 938        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
 939        "LIKE": lambda self: self._parse_create_like(),
 940        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
 941        "LOCK": lambda self: self._parse_locking(),
 942        "LOCKING": lambda self: self._parse_locking(),
 943        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
 944        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
 945        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
 946        "MODIFIES": lambda self: self._parse_modifies_property(),
 947        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
 948        "NO": lambda self: self._parse_no_property(),
 949        "ON": lambda self: self._parse_on_property(),
 950        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
 951        "OUTPUT": lambda self: self.expression(exp.OutputModelProperty, this=self._parse_schema()),
 952        "PARTITION": lambda self: self._parse_partitioned_of(),
 953        "PARTITION BY": lambda self: self._parse_partitioned_by(),
 954        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
 955        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
 956        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
 957        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
 958        "READS": lambda self: self._parse_reads_property(),
 959        "REMOTE": lambda self: self._parse_remote_with_connection(),
 960        "RETURNS": lambda self: self._parse_returns(),
 961        "STRICT": lambda self: self.expression(exp.StrictProperty),
 962        "STREAMING": lambda self: self.expression(exp.StreamingTableProperty),
 963        "ROW": lambda self: self._parse_row(),
 964        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
 965        "SAMPLE": lambda self: self.expression(
 966            exp.SampleProperty, this=self._match_text_seq("BY") and self._parse_bitwise()
 967        ),
 968        "SECURE": lambda self: self.expression(exp.SecureProperty),
 969        "SECURITY": lambda self: self._parse_security(),
 970        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
 971        "SETTINGS": lambda self: self._parse_settings_property(),
 972        "SHARING": lambda self: self._parse_property_assignment(exp.SharingProperty),
 973        "SORTKEY": lambda self: self._parse_sortkey(),
 974        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
 975        "STABLE": lambda self: self.expression(
 976            exp.StabilityProperty, this=exp.Literal.string("STABLE")
 977        ),
 978        "STORED": lambda self: self._parse_stored(),
 979        "SYSTEM_VERSIONING": lambda self: self._parse_system_versioning_property(),
 980        "TBLPROPERTIES": lambda self: self._parse_wrapped_properties(),
 981        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
 982        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
 983        "TO": lambda self: self._parse_to_table(),
 984        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
 985        "TRANSFORM": lambda self: self.expression(
 986            exp.TransformModelProperty, expressions=self._parse_wrapped_csv(self._parse_expression)
 987        ),
 988        "TTL": lambda self: self._parse_ttl(),
 989        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 990        "UNLOGGED": lambda self: self.expression(exp.UnloggedProperty),
 991        "VOLATILE": lambda self: self._parse_volatile_property(),
 992        "WITH": lambda self: self._parse_with_property(),
 993    }
 994
 995    CONSTRAINT_PARSERS = {
 996        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
 997        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
 998        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
 999        "CHARACTER SET": lambda self: self.expression(
1000            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
1001        ),
1002        "CHECK": lambda self: self.expression(
1003            exp.CheckColumnConstraint,
1004            this=self._parse_wrapped(self._parse_assignment),
1005            enforced=self._match_text_seq("ENFORCED"),
1006        ),
1007        "COLLATE": lambda self: self.expression(
1008            exp.CollateColumnConstraint,
1009            this=self._parse_identifier() or self._parse_column(),
1010        ),
1011        "COMMENT": lambda self: self.expression(
1012            exp.CommentColumnConstraint, this=self._parse_string()
1013        ),
1014        "COMPRESS": lambda self: self._parse_compress(),
1015        "CLUSTERED": lambda self: self.expression(
1016            exp.ClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
1017        ),
1018        "NONCLUSTERED": lambda self: self.expression(
1019            exp.NonClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
1020        ),
1021        "DEFAULT": lambda self: self.expression(
1022            exp.DefaultColumnConstraint, this=self._parse_bitwise()
1023        ),
1024        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
1025        "EPHEMERAL": lambda self: self.expression(
1026            exp.EphemeralColumnConstraint, this=self._parse_bitwise()
1027        ),
1028        "EXCLUDE": lambda self: self.expression(
1029            exp.ExcludeColumnConstraint, this=self._parse_index_params()
1030        ),
1031        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
1032        "FORMAT": lambda self: self.expression(
1033            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
1034        ),
1035        "GENERATED": lambda self: self._parse_generated_as_identity(),
1036        "IDENTITY": lambda self: self._parse_auto_increment(),
1037        "INLINE": lambda self: self._parse_inline(),
1038        "LIKE": lambda self: self._parse_create_like(),
1039        "NOT": lambda self: self._parse_not_constraint(),
1040        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
1041        "ON": lambda self: (
1042            self._match(TokenType.UPDATE)
1043            and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function())
1044        )
1045        or self.expression(exp.OnProperty, this=self._parse_id_var()),
1046        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
1047        "PERIOD": lambda self: self._parse_period_for_system_time(),
1048        "PRIMARY KEY": lambda self: self._parse_primary_key(),
1049        "REFERENCES": lambda self: self._parse_references(match=False),
1050        "TITLE": lambda self: self.expression(
1051            exp.TitleColumnConstraint, this=self._parse_var_or_string()
1052        ),
1053        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
1054        "UNIQUE": lambda self: self._parse_unique(),
1055        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
1056        "WITH": lambda self: self.expression(
1057            exp.Properties, expressions=self._parse_wrapped_properties()
1058        ),
1059    }
1060
1061    ALTER_PARSERS = {
1062        "ADD": lambda self: self._parse_alter_table_add(),
1063        "AS": lambda self: self._parse_select(),
1064        "ALTER": lambda self: self._parse_alter_table_alter(),
1065        "CLUSTER BY": lambda self: self._parse_cluster(wrapped=True),
1066        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
1067        "DROP": lambda self: self._parse_alter_table_drop(),
1068        "RENAME": lambda self: self._parse_alter_table_rename(),
1069        "SET": lambda self: self._parse_alter_table_set(),
1070        "SWAP": lambda self: self.expression(
1071            exp.SwapTable, this=self._match(TokenType.WITH) and self._parse_table(schema=True)
1072        ),
1073    }
1074
1075    ALTER_ALTER_PARSERS = {
1076        "DISTKEY": lambda self: self._parse_alter_diststyle(),
1077        "DISTSTYLE": lambda self: self._parse_alter_diststyle(),
1078        "SORTKEY": lambda self: self._parse_alter_sortkey(),
1079        "COMPOUND": lambda self: self._parse_alter_sortkey(compound=True),
1080    }
1081
1082    SCHEMA_UNNAMED_CONSTRAINTS = {
1083        "CHECK",
1084        "EXCLUDE",
1085        "FOREIGN KEY",
1086        "LIKE",
1087        "PERIOD",
1088        "PRIMARY KEY",
1089        "UNIQUE",
1090    }
1091
1092    NO_PAREN_FUNCTION_PARSERS = {
1093        "ANY": lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
1094        "CASE": lambda self: self._parse_case(),
1095        "CONNECT_BY_ROOT": lambda self: self.expression(
1096            exp.ConnectByRoot, this=self._parse_column()
1097        ),
1098        "IF": lambda self: self._parse_if(),
1099        "NEXT": lambda self: self._parse_next_value_for(),
1100    }
1101
1102    INVALID_FUNC_NAME_TOKENS = {
1103        TokenType.IDENTIFIER,
1104        TokenType.STRING,
1105    }
1106
1107    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
1108
1109    KEY_VALUE_DEFINITIONS = (exp.Alias, exp.EQ, exp.PropertyEQ, exp.Slice)
1110
1111    FUNCTION_PARSERS = {
1112        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
1113        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
1114        "DECODE": lambda self: self._parse_decode(),
1115        "EXTRACT": lambda self: self._parse_extract(),
1116        "GAP_FILL": lambda self: self._parse_gap_fill(),
1117        "JSON_OBJECT": lambda self: self._parse_json_object(),
1118        "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
1119        "JSON_TABLE": lambda self: self._parse_json_table(),
1120        "MATCH": lambda self: self._parse_match_against(),
1121        "NORMALIZE": lambda self: self._parse_normalize(),
1122        "OPENJSON": lambda self: self._parse_open_json(),
1123        "OVERLAY": lambda self: self._parse_overlay(),
1124        "POSITION": lambda self: self._parse_position(),
1125        "PREDICT": lambda self: self._parse_predict(),
1126        "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
1127        "STRING_AGG": lambda self: self._parse_string_agg(),
1128        "SUBSTRING": lambda self: self._parse_substring(),
1129        "TRIM": lambda self: self._parse_trim(),
1130        "TRY_CAST": lambda self: self._parse_cast(False, safe=True),
1131        "TRY_CONVERT": lambda self: self._parse_convert(False, safe=True),
1132    }
1133
1134    QUERY_MODIFIER_PARSERS = {
1135        TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
1136        TokenType.PREWHERE: lambda self: ("prewhere", self._parse_prewhere()),
1137        TokenType.WHERE: lambda self: ("where", self._parse_where()),
1138        TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
1139        TokenType.HAVING: lambda self: ("having", self._parse_having()),
1140        TokenType.QUALIFY: lambda self: ("qualify", self._parse_qualify()),
1141        TokenType.WINDOW: lambda self: ("windows", self._parse_window_clause()),
1142        TokenType.ORDER_BY: lambda self: ("order", self._parse_order()),
1143        TokenType.LIMIT: lambda self: ("limit", self._parse_limit()),
1144        TokenType.FETCH: lambda self: ("limit", self._parse_limit()),
1145        TokenType.OFFSET: lambda self: ("offset", self._parse_offset()),
1146        TokenType.FOR: lambda self: ("locks", self._parse_locks()),
1147        TokenType.LOCK: lambda self: ("locks", self._parse_locks()),
1148        TokenType.TABLE_SAMPLE: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
1149        TokenType.USING: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
1150        TokenType.CLUSTER_BY: lambda self: (
1151            "cluster",
1152            self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
1153        ),
1154        TokenType.DISTRIBUTE_BY: lambda self: (
1155            "distribute",
1156            self._parse_sort(exp.Distribute, TokenType.DISTRIBUTE_BY),
1157        ),
1158        TokenType.SORT_BY: lambda self: ("sort", self._parse_sort(exp.Sort, TokenType.SORT_BY)),
1159        TokenType.CONNECT_BY: lambda self: ("connect", self._parse_connect(skip_start_token=True)),
1160        TokenType.START_WITH: lambda self: ("connect", self._parse_connect()),
1161    }
1162
1163    SET_PARSERS = {
1164        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
1165        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
1166        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
1167        "TRANSACTION": lambda self: self._parse_set_transaction(),
1168    }
1169
1170    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
1171
1172    TYPE_LITERAL_PARSERS = {
1173        exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
1174    }
1175
1176    TYPE_CONVERTERS: t.Dict[exp.DataType.Type, t.Callable[[exp.DataType], exp.DataType]] = {}
1177
1178    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
1179
1180    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
1181
1182    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
1183    TRANSACTION_CHARACTERISTICS: OPTIONS_TYPE = {
1184        "ISOLATION": (
1185            ("LEVEL", "REPEATABLE", "READ"),
1186            ("LEVEL", "READ", "COMMITTED"),
1187            ("LEVEL", "READ", "UNCOMITTED"),
1188            ("LEVEL", "SERIALIZABLE"),
1189        ),
1190        "READ": ("WRITE", "ONLY"),
1191    }
1192
1193    CONFLICT_ACTIONS: OPTIONS_TYPE = dict.fromkeys(
1194        ("ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK", "UPDATE"), tuple()
1195    )
1196    CONFLICT_ACTIONS["DO"] = ("NOTHING", "UPDATE")
1197
1198    CREATE_SEQUENCE: OPTIONS_TYPE = {
1199        "SCALE": ("EXTEND", "NOEXTEND"),
1200        "SHARD": ("EXTEND", "NOEXTEND"),
1201        "NO": ("CYCLE", "CACHE", "MAXVALUE", "MINVALUE"),
1202        **dict.fromkeys(
1203            (
1204                "SESSION",
1205                "GLOBAL",
1206                "KEEP",
1207                "NOKEEP",
1208                "ORDER",
1209                "NOORDER",
1210                "NOCACHE",
1211                "CYCLE",
1212                "NOCYCLE",
1213                "NOMINVALUE",
1214                "NOMAXVALUE",
1215                "NOSCALE",
1216                "NOSHARD",
1217            ),
1218            tuple(),
1219        ),
1220    }
1221
1222    ISOLATED_LOADING_OPTIONS: OPTIONS_TYPE = {"FOR": ("ALL", "INSERT", "NONE")}
1223
1224    USABLES: OPTIONS_TYPE = dict.fromkeys(
1225        ("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA", "CATALOG"), tuple()
1226    )
1227
1228    CAST_ACTIONS: OPTIONS_TYPE = dict.fromkeys(("RENAME", "ADD"), ("FIELDS",))
1229
1230    SCHEMA_BINDING_OPTIONS: OPTIONS_TYPE = {
1231        "TYPE": ("EVOLUTION",),
1232        **dict.fromkeys(("BINDING", "COMPENSATION", "EVOLUTION"), tuple()),
1233    }
1234
1235    PROCEDURE_OPTIONS: OPTIONS_TYPE = {}
1236
1237    EXECUTE_AS_OPTIONS: OPTIONS_TYPE = dict.fromkeys(("CALLER", "SELF", "OWNER"), tuple())
1238
1239    KEY_CONSTRAINT_OPTIONS: OPTIONS_TYPE = {
1240        "NOT": ("ENFORCED",),
1241        "MATCH": (
1242            "FULL",
1243            "PARTIAL",
1244            "SIMPLE",
1245        ),
1246        "INITIALLY": ("DEFERRED", "IMMEDIATE"),
1247        **dict.fromkeys(("DEFERRABLE", "NORELY"), tuple()),
1248    }
1249
1250    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
1251
1252    CLONE_KEYWORDS = {"CLONE", "COPY"}
1253    HISTORICAL_DATA_PREFIX = {"AT", "BEFORE", "END"}
1254    HISTORICAL_DATA_KIND = {"TIMESTAMP", "OFFSET", "STATEMENT", "STREAM"}
1255
1256    OPCLASS_FOLLOW_KEYWORDS = {"ASC", "DESC", "NULLS", "WITH"}
1257
1258    OPTYPE_FOLLOW_TOKENS = {TokenType.COMMA, TokenType.R_PAREN}
1259
1260    TABLE_INDEX_HINT_TOKENS = {TokenType.FORCE, TokenType.IGNORE, TokenType.USE}
1261
1262    VIEW_ATTRIBUTES = {"ENCRYPTION", "SCHEMABINDING", "VIEW_METADATA"}
1263
1264    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
1265    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
1266    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
1267
1268    JSON_KEY_VALUE_SEPARATOR_TOKENS = {TokenType.COLON, TokenType.COMMA, TokenType.IS}
1269
1270    FETCH_TOKENS = ID_VAR_TOKENS - {TokenType.ROW, TokenType.ROWS, TokenType.PERCENT}
1271
1272    ADD_CONSTRAINT_TOKENS = {
1273        TokenType.CONSTRAINT,
1274        TokenType.FOREIGN_KEY,
1275        TokenType.INDEX,
1276        TokenType.KEY,
1277        TokenType.PRIMARY_KEY,
1278        TokenType.UNIQUE,
1279    }
1280
1281    DISTINCT_TOKENS = {TokenType.DISTINCT}
1282
1283    NULL_TOKENS = {TokenType.NULL}
1284
1285    UNNEST_OFFSET_ALIAS_TOKENS = ID_VAR_TOKENS - SET_OPERATIONS
1286
1287    SELECT_START_TOKENS = {TokenType.L_PAREN, TokenType.WITH, TokenType.SELECT}
1288
1289    COPY_INTO_VARLEN_OPTIONS = {"FILE_FORMAT", "COPY_OPTIONS", "FORMAT_OPTIONS", "CREDENTIAL"}
1290
1291    IS_JSON_PREDICATE_KIND = {"VALUE", "SCALAR", "ARRAY", "OBJECT"}
1292
1293    ODBC_DATETIME_LITERALS = {
1294        "d": exp.Date,
1295        "t": exp.Time,
1296        "ts": exp.Timestamp,
1297    }
1298
1299    ON_CONDITION_TOKENS = {"ERROR", "NULL", "TRUE", "FALSE", "EMPTY"}
1300
1301    PRIVILEGE_FOLLOW_TOKENS = {TokenType.ON, TokenType.COMMA, TokenType.L_PAREN}
1302
1303    # The style options for the DESCRIBE statement
1304    DESCRIBE_STYLES = {"ANALYZE", "EXTENDED", "FORMATTED", "HISTORY"}
1305
1306    OPERATION_MODIFIERS: t.Set[str] = set()
1307
1308    STRICT_CAST = True
1309
1310    PREFIXED_PIVOT_COLUMNS = False
1311    IDENTIFY_PIVOT_STRINGS = False
1312
1313    LOG_DEFAULTS_TO_LN = False
1314
1315    # Whether ADD is present for each column added by ALTER TABLE
1316    ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
1317
1318    # Whether the table sample clause expects CSV syntax
1319    TABLESAMPLE_CSV = False
1320
1321    # The default method used for table sampling
1322    DEFAULT_SAMPLING_METHOD: t.Optional[str] = None
1323
1324    # Whether the SET command needs a delimiter (e.g. "=") for assignments
1325    SET_REQUIRES_ASSIGNMENT_DELIMITER = True
1326
1327    # Whether the TRIM function expects the characters to trim as its first argument
1328    TRIM_PATTERN_FIRST = False
1329
1330    # Whether string aliases are supported `SELECT COUNT(*) 'count'`
1331    STRING_ALIASES = False
1332
1333    # Whether query modifiers such as LIMIT are attached to the UNION node (vs its right operand)
1334    MODIFIERS_ATTACHED_TO_SET_OP = True
1335    SET_OP_MODIFIERS = {"order", "limit", "offset"}
1336
1337    # Whether to parse IF statements that aren't followed by a left parenthesis as commands
1338    NO_PAREN_IF_COMMANDS = True
1339
1340    # Whether the -> and ->> operators expect documents of type JSON (e.g. Postgres)
1341    JSON_ARROWS_REQUIRE_JSON_TYPE = False
1342
1343    # Whether the `:` operator is used to extract a value from a VARIANT column
1344    COLON_IS_VARIANT_EXTRACT = False
1345
1346    # Whether or not a VALUES keyword needs to be followed by '(' to form a VALUES clause.
1347    # If this is True and '(' is not found, the keyword will be treated as an identifier
1348    VALUES_FOLLOWED_BY_PAREN = True
1349
1350    # Whether implicit unnesting is supported, e.g. SELECT 1 FROM y.z AS z, z.a (Redshift)
1351    SUPPORTS_IMPLICIT_UNNEST = False
1352
1353    # Whether or not interval spans are supported, INTERVAL 1 YEAR TO MONTHS
1354    INTERVAL_SPANS = True
1355
1356    # Whether a PARTITION clause can follow a table reference
1357    SUPPORTS_PARTITION_SELECTION = False
1358
1359    __slots__ = (
1360        "error_level",
1361        "error_message_context",
1362        "max_errors",
1363        "dialect",
1364        "sql",
1365        "errors",
1366        "_tokens",
1367        "_index",
1368        "_curr",
1369        "_next",
1370        "_prev",
1371        "_prev_comments",
1372    )
1373
1374    # Autofilled
1375    SHOW_TRIE: t.Dict = {}
1376    SET_TRIE: t.Dict = {}
1377
1378    def __init__(
1379        self,
1380        error_level: t.Optional[ErrorLevel] = None,
1381        error_message_context: int = 100,
1382        max_errors: int = 3,
1383        dialect: DialectType = None,
1384    ):
1385        from sqlglot.dialects import Dialect
1386
1387        self.error_level = error_level or ErrorLevel.IMMEDIATE
1388        self.error_message_context = error_message_context
1389        self.max_errors = max_errors
1390        self.dialect = Dialect.get_or_raise(dialect)
1391        self.reset()
1392
1393    def reset(self):
1394        self.sql = ""
1395        self.errors = []
1396        self._tokens = []
1397        self._index = 0
1398        self._curr = None
1399        self._next = None
1400        self._prev = None
1401        self._prev_comments = None
1402
1403    def parse(
1404        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1405    ) -> t.List[t.Optional[exp.Expression]]:
1406        """
1407        Parses a list of tokens and returns a list of syntax trees, one tree
1408        per parsed SQL statement.
1409
1410        Args:
1411            raw_tokens: The list of tokens.
1412            sql: The original SQL string, used to produce helpful debug messages.
1413
1414        Returns:
1415            The list of the produced syntax trees.
1416        """
1417        return self._parse(
1418            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1419        )
1420
1421    def parse_into(
1422        self,
1423        expression_types: exp.IntoType,
1424        raw_tokens: t.List[Token],
1425        sql: t.Optional[str] = None,
1426    ) -> t.List[t.Optional[exp.Expression]]:
1427        """
1428        Parses a list of tokens into a given Expression type. If a collection of Expression
1429        types is given instead, this method will try to parse the token list into each one
1430        of them, stopping at the first for which the parsing succeeds.
1431
1432        Args:
1433            expression_types: The expression type(s) to try and parse the token list into.
1434            raw_tokens: The list of tokens.
1435            sql: The original SQL string, used to produce helpful debug messages.
1436
1437        Returns:
1438            The target Expression.
1439        """
1440        errors = []
1441        for expression_type in ensure_list(expression_types):
1442            parser = self.EXPRESSION_PARSERS.get(expression_type)
1443            if not parser:
1444                raise TypeError(f"No parser registered for {expression_type}")
1445
1446            try:
1447                return self._parse(parser, raw_tokens, sql)
1448            except ParseError as e:
1449                e.errors[0]["into_expression"] = expression_type
1450                errors.append(e)
1451
1452        raise ParseError(
1453            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1454            errors=merge_errors(errors),
1455        ) from errors[-1]
1456
1457    def _parse(
1458        self,
1459        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
1460        raw_tokens: t.List[Token],
1461        sql: t.Optional[str] = None,
1462    ) -> t.List[t.Optional[exp.Expression]]:
1463        self.reset()
1464        self.sql = sql or ""
1465
1466        total = len(raw_tokens)
1467        chunks: t.List[t.List[Token]] = [[]]
1468
1469        for i, token in enumerate(raw_tokens):
1470            if token.token_type == TokenType.SEMICOLON:
1471                if token.comments:
1472                    chunks.append([token])
1473
1474                if i < total - 1:
1475                    chunks.append([])
1476            else:
1477                chunks[-1].append(token)
1478
1479        expressions = []
1480
1481        for tokens in chunks:
1482            self._index = -1
1483            self._tokens = tokens
1484            self._advance()
1485
1486            expressions.append(parse_method(self))
1487
1488            if self._index < len(self._tokens):
1489                self.raise_error("Invalid expression / Unexpected token")
1490
1491            self.check_errors()
1492
1493        return expressions
1494
1495    def check_errors(self) -> None:
1496        """Logs or raises any found errors, depending on the chosen error level setting."""
1497        if self.error_level == ErrorLevel.WARN:
1498            for error in self.errors:
1499                logger.error(str(error))
1500        elif self.error_level == ErrorLevel.RAISE and self.errors:
1501            raise ParseError(
1502                concat_messages(self.errors, self.max_errors),
1503                errors=merge_errors(self.errors),
1504            )
1505
1506    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1507        """
1508        Appends an error in the list of recorded errors or raises it, depending on the chosen
1509        error level setting.
1510        """
1511        token = token or self._curr or self._prev or Token.string("")
1512        start = token.start
1513        end = token.end + 1
1514        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1515        highlight = self.sql[start:end]
1516        end_context = self.sql[end : end + self.error_message_context]
1517
1518        error = ParseError.new(
1519            f"{message}. Line {token.line}, Col: {token.col}.\n"
1520            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1521            description=message,
1522            line=token.line,
1523            col=token.col,
1524            start_context=start_context,
1525            highlight=highlight,
1526            end_context=end_context,
1527        )
1528
1529        if self.error_level == ErrorLevel.IMMEDIATE:
1530            raise error
1531
1532        self.errors.append(error)
1533
1534    def expression(
1535        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1536    ) -> E:
1537        """
1538        Creates a new, validated Expression.
1539
1540        Args:
1541            exp_class: The expression class to instantiate.
1542            comments: An optional list of comments to attach to the expression.
1543            kwargs: The arguments to set for the expression along with their respective values.
1544
1545        Returns:
1546            The target expression.
1547        """
1548        instance = exp_class(**kwargs)
1549        instance.add_comments(comments) if comments else self._add_comments(instance)
1550        return self.validate_expression(instance)
1551
1552    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
1553        if expression and self._prev_comments:
1554            expression.add_comments(self._prev_comments)
1555            self._prev_comments = None
1556
1557    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1558        """
1559        Validates an Expression, making sure that all its mandatory arguments are set.
1560
1561        Args:
1562            expression: The expression to validate.
1563            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1564
1565        Returns:
1566            The validated expression.
1567        """
1568        if self.error_level != ErrorLevel.IGNORE:
1569            for error_message in expression.error_messages(args):
1570                self.raise_error(error_message)
1571
1572        return expression
1573
1574    def _find_sql(self, start: Token, end: Token) -> str:
1575        return self.sql[start.start : end.end + 1]
1576
1577    def _is_connected(self) -> bool:
1578        return self._prev and self._curr and self._prev.end + 1 == self._curr.start
1579
1580    def _advance(self, times: int = 1) -> None:
1581        self._index += times
1582        self._curr = seq_get(self._tokens, self._index)
1583        self._next = seq_get(self._tokens, self._index + 1)
1584
1585        if self._index > 0:
1586            self._prev = self._tokens[self._index - 1]
1587            self._prev_comments = self._prev.comments
1588        else:
1589            self._prev = None
1590            self._prev_comments = None
1591
1592    def _retreat(self, index: int) -> None:
1593        if index != self._index:
1594            self._advance(index - self._index)
1595
1596    def _warn_unsupported(self) -> None:
1597        if len(self._tokens) <= 1:
1598            return
1599
1600        # We use _find_sql because self.sql may comprise multiple chunks, and we're only
1601        # interested in emitting a warning for the one being currently processed.
1602        sql = self._find_sql(self._tokens[0], self._tokens[-1])[: self.error_message_context]
1603
1604        logger.warning(
1605            f"'{sql}' contains unsupported syntax. Falling back to parsing as a 'Command'."
1606        )
1607
1608    def _parse_command(self) -> exp.Command:
1609        self._warn_unsupported()
1610        return self.expression(
1611            exp.Command,
1612            comments=self._prev_comments,
1613            this=self._prev.text.upper(),
1614            expression=self._parse_string(),
1615        )
1616
1617    def _try_parse(self, parse_method: t.Callable[[], T], retreat: bool = False) -> t.Optional[T]:
1618        """
1619        Attemps to backtrack if a parse function that contains a try/catch internally raises an error.
1620        This behavior can be different depending on the uset-set ErrorLevel, so _try_parse aims to
1621        solve this by setting & resetting the parser state accordingly
1622        """
1623        index = self._index
1624        error_level = self.error_level
1625
1626        self.error_level = ErrorLevel.IMMEDIATE
1627        try:
1628            this = parse_method()
1629        except ParseError:
1630            this = None
1631        finally:
1632            if not this or retreat:
1633                self._retreat(index)
1634            self.error_level = error_level
1635
1636        return this
1637
1638    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
1639        start = self._prev
1640        exists = self._parse_exists() if allow_exists else None
1641
1642        self._match(TokenType.ON)
1643
1644        materialized = self._match_text_seq("MATERIALIZED")
1645        kind = self._match_set(self.CREATABLES) and self._prev
1646        if not kind:
1647            return self._parse_as_command(start)
1648
1649        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1650            this = self._parse_user_defined_function(kind=kind.token_type)
1651        elif kind.token_type == TokenType.TABLE:
1652            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
1653        elif kind.token_type == TokenType.COLUMN:
1654            this = self._parse_column()
1655        else:
1656            this = self._parse_id_var()
1657
1658        self._match(TokenType.IS)
1659
1660        return self.expression(
1661            exp.Comment,
1662            this=this,
1663            kind=kind.text,
1664            expression=self._parse_string(),
1665            exists=exists,
1666            materialized=materialized,
1667        )
1668
1669    def _parse_to_table(
1670        self,
1671    ) -> exp.ToTableProperty:
1672        table = self._parse_table_parts(schema=True)
1673        return self.expression(exp.ToTableProperty, this=table)
1674
1675    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
1676    def _parse_ttl(self) -> exp.Expression:
1677        def _parse_ttl_action() -> t.Optional[exp.Expression]:
1678            this = self._parse_bitwise()
1679
1680            if self._match_text_seq("DELETE"):
1681                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
1682            if self._match_text_seq("RECOMPRESS"):
1683                return self.expression(
1684                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
1685                )
1686            if self._match_text_seq("TO", "DISK"):
1687                return self.expression(
1688                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
1689                )
1690            if self._match_text_seq("TO", "VOLUME"):
1691                return self.expression(
1692                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
1693                )
1694
1695            return this
1696
1697        expressions = self._parse_csv(_parse_ttl_action)
1698        where = self._parse_where()
1699        group = self._parse_group()
1700
1701        aggregates = None
1702        if group and self._match(TokenType.SET):
1703            aggregates = self._parse_csv(self._parse_set_item)
1704
1705        return self.expression(
1706            exp.MergeTreeTTL,
1707            expressions=expressions,
1708            where=where,
1709            group=group,
1710            aggregates=aggregates,
1711        )
1712
1713    def _parse_statement(self) -> t.Optional[exp.Expression]:
1714        if self._curr is None:
1715            return None
1716
1717        if self._match_set(self.STATEMENT_PARSERS):
1718            return self.STATEMENT_PARSERS[self._prev.token_type](self)
1719
1720        if self._match_set(self.dialect.tokenizer.COMMANDS):
1721            return self._parse_command()
1722
1723        expression = self._parse_expression()
1724        expression = self._parse_set_operations(expression) if expression else self._parse_select()
1725        return self._parse_query_modifiers(expression)
1726
1727    def _parse_drop(self, exists: bool = False) -> exp.Drop | exp.Command:
1728        start = self._prev
1729        temporary = self._match(TokenType.TEMPORARY)
1730        materialized = self._match_text_seq("MATERIALIZED")
1731
1732        kind = self._match_set(self.CREATABLES) and self._prev.text.upper()
1733        if not kind:
1734            return self._parse_as_command(start)
1735
1736        concurrently = self._match_text_seq("CONCURRENTLY")
1737        if_exists = exists or self._parse_exists()
1738        table = self._parse_table_parts(
1739            schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
1740        )
1741
1742        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
1743
1744        if self._match(TokenType.L_PAREN, advance=False):
1745            expressions = self._parse_wrapped_csv(self._parse_types)
1746        else:
1747            expressions = None
1748
1749        return self.expression(
1750            exp.Drop,
1751            comments=start.comments,
1752            exists=if_exists,
1753            this=table,
1754            expressions=expressions,
1755            kind=self.dialect.CREATABLE_KIND_MAPPING.get(kind) or kind,
1756            temporary=temporary,
1757            materialized=materialized,
1758            cascade=self._match_text_seq("CASCADE"),
1759            constraints=self._match_text_seq("CONSTRAINTS"),
1760            purge=self._match_text_seq("PURGE"),
1761            cluster=cluster,
1762            concurrently=concurrently,
1763        )
1764
1765    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
1766        return (
1767            self._match_text_seq("IF")
1768            and (not not_ or self._match(TokenType.NOT))
1769            and self._match(TokenType.EXISTS)
1770        )
1771
1772    def _parse_create(self) -> exp.Create | exp.Command:
1773        # Note: this can't be None because we've matched a statement parser
1774        start = self._prev
1775        comments = self._prev_comments
1776
1777        replace = (
1778            start.token_type == TokenType.REPLACE
1779            or self._match_pair(TokenType.OR, TokenType.REPLACE)
1780            or self._match_pair(TokenType.OR, TokenType.ALTER)
1781        )
1782        refresh = self._match_pair(TokenType.OR, TokenType.REFRESH)
1783
1784        unique = self._match(TokenType.UNIQUE)
1785
1786        if self._match_text_seq("CLUSTERED", "COLUMNSTORE"):
1787            clustered = True
1788        elif self._match_text_seq("NONCLUSTERED", "COLUMNSTORE") or self._match_text_seq(
1789            "COLUMNSTORE"
1790        ):
1791            clustered = False
1792        else:
1793            clustered = None
1794
1795        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
1796            self._advance()
1797
1798        properties = None
1799        create_token = self._match_set(self.CREATABLES) and self._prev
1800
1801        if not create_token:
1802            # exp.Properties.Location.POST_CREATE
1803            properties = self._parse_properties()
1804            create_token = self._match_set(self.CREATABLES) and self._prev
1805
1806            if not properties or not create_token:
1807                return self._parse_as_command(start)
1808
1809        concurrently = self._match_text_seq("CONCURRENTLY")
1810        exists = self._parse_exists(not_=True)
1811        this = None
1812        expression: t.Optional[exp.Expression] = None
1813        indexes = None
1814        no_schema_binding = None
1815        begin = None
1816        end = None
1817        clone = None
1818
1819        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
1820            nonlocal properties
1821            if properties and temp_props:
1822                properties.expressions.extend(temp_props.expressions)
1823            elif temp_props:
1824                properties = temp_props
1825
1826        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1827            this = self._parse_user_defined_function(kind=create_token.token_type)
1828
1829            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
1830            extend_props(self._parse_properties())
1831
1832            expression = self._match(TokenType.ALIAS) and self._parse_heredoc()
1833            extend_props(self._parse_properties())
1834
1835            if not expression:
1836                if self._match(TokenType.COMMAND):
1837                    expression = self._parse_as_command(self._prev)
1838                else:
1839                    begin = self._match(TokenType.BEGIN)
1840                    return_ = self._match_text_seq("RETURN")
1841
1842                    if self._match(TokenType.STRING, advance=False):
1843                        # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
1844                        # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
1845                        expression = self._parse_string()
1846                        extend_props(self._parse_properties())
1847                    else:
1848                        expression = self._parse_user_defined_function_expression()
1849
1850                    end = self._match_text_seq("END")
1851
1852                    if return_:
1853                        expression = self.expression(exp.Return, this=expression)
1854        elif create_token.token_type == TokenType.INDEX:
1855            # Postgres allows anonymous indexes, eg. CREATE INDEX IF NOT EXISTS ON t(c)
1856            if not self._match(TokenType.ON):
1857                index = self._parse_id_var()
1858                anonymous = False
1859            else:
1860                index = None
1861                anonymous = True
1862
1863            this = self._parse_index(index=index, anonymous=anonymous)
1864        elif create_token.token_type in self.DB_CREATABLES:
1865            table_parts = self._parse_table_parts(
1866                schema=True, is_db_reference=create_token.token_type == TokenType.SCHEMA
1867            )
1868
1869            # exp.Properties.Location.POST_NAME
1870            self._match(TokenType.COMMA)
1871            extend_props(self._parse_properties(before=True))
1872
1873            this = self._parse_schema(this=table_parts)
1874
1875            # exp.Properties.Location.POST_SCHEMA and POST_WITH
1876            extend_props(self._parse_properties())
1877
1878            self._match(TokenType.ALIAS)
1879            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
1880                # exp.Properties.Location.POST_ALIAS
1881                extend_props(self._parse_properties())
1882
1883            if create_token.token_type == TokenType.SEQUENCE:
1884                expression = self._parse_types()
1885                extend_props(self._parse_properties())
1886            else:
1887                expression = self._parse_ddl_select()
1888
1889            if create_token.token_type == TokenType.TABLE:
1890                # exp.Properties.Location.POST_EXPRESSION
1891                extend_props(self._parse_properties())
1892
1893                indexes = []
1894                while True:
1895                    index = self._parse_index()
1896
1897                    # exp.Properties.Location.POST_INDEX
1898                    extend_props(self._parse_properties())
1899                    if not index:
1900                        break
1901                    else:
1902                        self._match(TokenType.COMMA)
1903                        indexes.append(index)
1904            elif create_token.token_type == TokenType.VIEW:
1905                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
1906                    no_schema_binding = True
1907
1908            shallow = self._match_text_seq("SHALLOW")
1909
1910            if self._match_texts(self.CLONE_KEYWORDS):
1911                copy = self._prev.text.lower() == "copy"
1912                clone = self.expression(
1913                    exp.Clone, this=self._parse_table(schema=True), shallow=shallow, copy=copy
1914                )
1915
1916        if self._curr and not self._match_set((TokenType.R_PAREN, TokenType.COMMA), advance=False):
1917            return self._parse_as_command(start)
1918
1919        create_kind_text = create_token.text.upper()
1920        return self.expression(
1921            exp.Create,
1922            comments=comments,
1923            this=this,
1924            kind=self.dialect.CREATABLE_KIND_MAPPING.get(create_kind_text) or create_kind_text,
1925            replace=replace,
1926            refresh=refresh,
1927            unique=unique,
1928            expression=expression,
1929            exists=exists,
1930            properties=properties,
1931            indexes=indexes,
1932            no_schema_binding=no_schema_binding,
1933            begin=begin,
1934            end=end,
1935            clone=clone,
1936            concurrently=concurrently,
1937            clustered=clustered,
1938        )
1939
1940    def _parse_sequence_properties(self) -> t.Optional[exp.SequenceProperties]:
1941        seq = exp.SequenceProperties()
1942
1943        options = []
1944        index = self._index
1945
1946        while self._curr:
1947            self._match(TokenType.COMMA)
1948            if self._match_text_seq("INCREMENT"):
1949                self._match_text_seq("BY")
1950                self._match_text_seq("=")
1951                seq.set("increment", self._parse_term())
1952            elif self._match_text_seq("MINVALUE"):
1953                seq.set("minvalue", self._parse_term())
1954            elif self._match_text_seq("MAXVALUE"):
1955                seq.set("maxvalue", self._parse_term())
1956            elif self._match(TokenType.START_WITH) or self._match_text_seq("START"):
1957                self._match_text_seq("=")
1958                seq.set("start", self._parse_term())
1959            elif self._match_text_seq("CACHE"):
1960                # T-SQL allows empty CACHE which is initialized dynamically
1961                seq.set("cache", self._parse_number() or True)
1962            elif self._match_text_seq("OWNED", "BY"):
1963                # "OWNED BY NONE" is the default
1964                seq.set("owned", None if self._match_text_seq("NONE") else self._parse_column())
1965            else:
1966                opt = self._parse_var_from_options(self.CREATE_SEQUENCE, raise_unmatched=False)
1967                if opt:
1968                    options.append(opt)
1969                else:
1970                    break
1971
1972        seq.set("options", options if options else None)
1973        return None if self._index == index else seq
1974
1975    def _parse_property_before(self) -> t.Optional[exp.Expression]:
1976        # only used for teradata currently
1977        self._match(TokenType.COMMA)
1978
1979        kwargs = {
1980            "no": self._match_text_seq("NO"),
1981            "dual": self._match_text_seq("DUAL"),
1982            "before": self._match_text_seq("BEFORE"),
1983            "default": self._match_text_seq("DEFAULT"),
1984            "local": (self._match_text_seq("LOCAL") and "LOCAL")
1985            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
1986            "after": self._match_text_seq("AFTER"),
1987            "minimum": self._match_texts(("MIN", "MINIMUM")),
1988            "maximum": self._match_texts(("MAX", "MAXIMUM")),
1989        }
1990
1991        if self._match_texts(self.PROPERTY_PARSERS):
1992            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
1993            try:
1994                return parser(self, **{k: v for k, v in kwargs.items() if v})
1995            except TypeError:
1996                self.raise_error(f"Cannot parse property '{self._prev.text}'")
1997
1998        return None
1999
2000    def _parse_wrapped_properties(self) -> t.List[exp.Expression]:
2001        return self._parse_wrapped_csv(self._parse_property)
2002
2003    def _parse_property(self) -> t.Optional[exp.Expression]:
2004        if self._match_texts(self.PROPERTY_PARSERS):
2005            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
2006
2007        if self._match(TokenType.DEFAULT) and self._match_texts(self.PROPERTY_PARSERS):
2008            return self.PROPERTY_PARSERS[self._prev.text.upper()](self, default=True)
2009
2010        if self._match_text_seq("COMPOUND", "SORTKEY"):
2011            return self._parse_sortkey(compound=True)
2012
2013        if self._match_text_seq("SQL", "SECURITY"):
2014            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
2015
2016        index = self._index
2017        key = self._parse_column()
2018
2019        if not self._match(TokenType.EQ):
2020            self._retreat(index)
2021            return self._parse_sequence_properties()
2022
2023        # Transform the key to exp.Dot if it's dotted identifiers wrapped in exp.Column or to exp.Var otherwise
2024        if isinstance(key, exp.Column):
2025            key = key.to_dot() if len(key.parts) > 1 else exp.var(key.name)
2026
2027        value = self._parse_bitwise() or self._parse_var(any_token=True)
2028
2029        # Transform the value to exp.Var if it was parsed as exp.Column(exp.Identifier())
2030        if isinstance(value, exp.Column):
2031            value = exp.var(value.name)
2032
2033        return self.expression(exp.Property, this=key, value=value)
2034
2035    def _parse_stored(self) -> exp.FileFormatProperty:
2036        self._match(TokenType.ALIAS)
2037
2038        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
2039        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
2040
2041        return self.expression(
2042            exp.FileFormatProperty,
2043            this=(
2044                self.expression(
2045                    exp.InputOutputFormat, input_format=input_format, output_format=output_format
2046                )
2047                if input_format or output_format
2048                else self._parse_var_or_string() or self._parse_number() or self._parse_id_var()
2049            ),
2050        )
2051
2052    def _parse_unquoted_field(self) -> t.Optional[exp.Expression]:
2053        field = self._parse_field()
2054        if isinstance(field, exp.Identifier) and not field.quoted:
2055            field = exp.var(field)
2056
2057        return field
2058
2059    def _parse_property_assignment(self, exp_class: t.Type[E], **kwargs: t.Any) -> E:
2060        self._match(TokenType.EQ)
2061        self._match(TokenType.ALIAS)
2062
2063        return self.expression(exp_class, this=self._parse_unquoted_field(), **kwargs)
2064
2065    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
2066        properties = []
2067        while True:
2068            if before:
2069                prop = self._parse_property_before()
2070            else:
2071                prop = self._parse_property()
2072            if not prop:
2073                break
2074            for p in ensure_list(prop):
2075                properties.append(p)
2076
2077        if properties:
2078            return self.expression(exp.Properties, expressions=properties)
2079
2080        return None
2081
2082    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
2083        return self.expression(
2084            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
2085        )
2086
2087    def _parse_security(self) -> t.Optional[exp.SecurityProperty]:
2088        if self._match_texts(("DEFINER", "INVOKER")):
2089            security_specifier = self._prev.text.upper()
2090            return self.expression(exp.SecurityProperty, this=security_specifier)
2091        return None
2092
2093    def _parse_settings_property(self) -> exp.SettingsProperty:
2094        return self.expression(
2095            exp.SettingsProperty, expressions=self._parse_csv(self._parse_assignment)
2096        )
2097
2098    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
2099        if self._index >= 2:
2100            pre_volatile_token = self._tokens[self._index - 2]
2101        else:
2102            pre_volatile_token = None
2103
2104        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
2105            return exp.VolatileProperty()
2106
2107        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
2108
2109    def _parse_retention_period(self) -> exp.Var:
2110        # Parse TSQL's HISTORY_RETENTION_PERIOD: {INFINITE | <number> DAY | DAYS | MONTH ...}
2111        number = self._parse_number()
2112        number_str = f"{number} " if number else ""
2113        unit = self._parse_var(any_token=True)
2114        return exp.var(f"{number_str}{unit}")
2115
2116    def _parse_system_versioning_property(
2117        self, with_: bool = False
2118    ) -> exp.WithSystemVersioningProperty:
2119        self._match(TokenType.EQ)
2120        prop = self.expression(
2121            exp.WithSystemVersioningProperty,
2122            **{  # type: ignore
2123                "on": True,
2124                "with": with_,
2125            },
2126        )
2127
2128        if self._match_text_seq("OFF"):
2129            prop.set("on", False)
2130            return prop
2131
2132        self._match(TokenType.ON)
2133        if self._match(TokenType.L_PAREN):
2134            while self._curr and not self._match(TokenType.R_PAREN):
2135                if self._match_text_seq("HISTORY_TABLE", "="):
2136                    prop.set("this", self._parse_table_parts())
2137                elif self._match_text_seq("DATA_CONSISTENCY_CHECK", "="):
2138                    prop.set("data_consistency", self._advance_any() and self._prev.text.upper())
2139                elif self._match_text_seq("HISTORY_RETENTION_PERIOD", "="):
2140                    prop.set("retention_period", self._parse_retention_period())
2141
2142                self._match(TokenType.COMMA)
2143
2144        return prop
2145
2146    def _parse_data_deletion_property(self) -> exp.DataDeletionProperty:
2147        self._match(TokenType.EQ)
2148        on = self._match_text_seq("ON") or not self._match_text_seq("OFF")
2149        prop = self.expression(exp.DataDeletionProperty, on=on)
2150
2151        if self._match(TokenType.L_PAREN):
2152            while self._curr and not self._match(TokenType.R_PAREN):
2153                if self._match_text_seq("FILTER_COLUMN", "="):
2154                    prop.set("filter_column", self._parse_column())
2155                elif self._match_text_seq("RETENTION_PERIOD", "="):
2156                    prop.set("retention_period", self._parse_retention_period())
2157
2158                self._match(TokenType.COMMA)
2159
2160        return prop
2161
2162    def _parse_distributed_property(self) -> exp.DistributedByProperty:
2163        kind = "HASH"
2164        expressions: t.Optional[t.List[exp.Expression]] = None
2165        if self._match_text_seq("BY", "HASH"):
2166            expressions = self._parse_wrapped_csv(self._parse_id_var)
2167        elif self._match_text_seq("BY", "RANDOM"):
2168            kind = "RANDOM"
2169
2170        # If the BUCKETS keyword is not present, the number of buckets is AUTO
2171        buckets: t.Optional[exp.Expression] = None
2172        if self._match_text_seq("BUCKETS") and not self._match_text_seq("AUTO"):
2173            buckets = self._parse_number()
2174
2175        return self.expression(
2176            exp.DistributedByProperty,
2177            expressions=expressions,
2178            kind=kind,
2179            buckets=buckets,
2180            order=self._parse_order(),
2181        )
2182
2183    def _parse_duplicate(self) -> exp.DuplicateKeyProperty:
2184        self._match_text_seq("KEY")
2185        expressions = self._parse_wrapped_csv(self._parse_id_var, optional=False)
2186        return self.expression(exp.DuplicateKeyProperty, expressions=expressions)
2187
2188    def _parse_with_property(self) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
2189        if self._match_text_seq("(", "SYSTEM_VERSIONING"):
2190            prop = self._parse_system_versioning_property(with_=True)
2191            self._match_r_paren()
2192            return prop
2193
2194        if self._match(TokenType.L_PAREN, advance=False):
2195            return self._parse_wrapped_properties()
2196
2197        if self._match_text_seq("JOURNAL"):
2198            return self._parse_withjournaltable()
2199
2200        if self._match_texts(self.VIEW_ATTRIBUTES):
2201            return self.expression(exp.ViewAttributeProperty, this=self._prev.text.upper())
2202
2203        if self._match_text_seq("DATA"):
2204            return self._parse_withdata(no=False)
2205        elif self._match_text_seq("NO", "DATA"):
2206            return self._parse_withdata(no=True)
2207
2208        if self._match(TokenType.SERDE_PROPERTIES, advance=False):
2209            return self._parse_serde_properties(with_=True)
2210
2211        if self._match(TokenType.SCHEMA):
2212            return self.expression(
2213                exp.WithSchemaBindingProperty,
2214                this=self._parse_var_from_options(self.SCHEMA_BINDING_OPTIONS),
2215            )
2216
2217        if self._match_texts(self.PROCEDURE_OPTIONS, advance=False):
2218            return self.expression(
2219                exp.WithProcedureOptions, expressions=self._parse_csv(self._parse_procedure_option)
2220            )
2221
2222        if not self._next:
2223            return None
2224
2225        return self._parse_withisolatedloading()
2226
2227    def _parse_procedure_option(self) -> exp.Expression | None:
2228        if self._match_text_seq("EXECUTE", "AS"):
2229            return self.expression(
2230                exp.ExecuteAsProperty,
2231                this=self._parse_var_from_options(self.EXECUTE_AS_OPTIONS, raise_unmatched=False)
2232                or self._parse_string(),
2233            )
2234
2235        return self._parse_var_from_options(self.PROCEDURE_OPTIONS)
2236
2237    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
2238    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
2239        self._match(TokenType.EQ)
2240
2241        user = self._parse_id_var()
2242        self._match(TokenType.PARAMETER)
2243        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
2244
2245        if not user or not host:
2246            return None
2247
2248        return exp.DefinerProperty(this=f"{user}@{host}")
2249
2250    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
2251        self._match(TokenType.TABLE)
2252        self._match(TokenType.EQ)
2253        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
2254
2255    def _parse_log(self, no: bool = False) -> exp.LogProperty:
2256        return self.expression(exp.LogProperty, no=no)
2257
2258    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
2259        return self.expression(exp.JournalProperty, **kwargs)
2260
2261    def _parse_checksum(self) -> exp.ChecksumProperty:
2262        self._match(TokenType.EQ)
2263
2264        on = None
2265        if self._match(TokenType.ON):
2266            on = True
2267        elif self._match_text_seq("OFF"):
2268            on = False
2269
2270        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
2271
2272    def _parse_cluster(self, wrapped: bool = False) -> exp.Cluster:
2273        return self.expression(
2274            exp.Cluster,
2275            expressions=(
2276                self._parse_wrapped_csv(self._parse_ordered)
2277                if wrapped
2278                else self._parse_csv(self._parse_ordered)
2279            ),
2280        )
2281
2282    def _parse_clustered_by(self) -> exp.ClusteredByProperty:
2283        self._match_text_seq("BY")
2284
2285        self._match_l_paren()
2286        expressions = self._parse_csv(self._parse_column)
2287        self._match_r_paren()
2288
2289        if self._match_text_seq("SORTED", "BY"):
2290            self._match_l_paren()
2291            sorted_by = self._parse_csv(self._parse_ordered)
2292            self._match_r_paren()
2293        else:
2294            sorted_by = None
2295
2296        self._match(TokenType.INTO)
2297        buckets = self._parse_number()
2298        self._match_text_seq("BUCKETS")
2299
2300        return self.expression(
2301            exp.ClusteredByProperty,
2302            expressions=expressions,
2303            sorted_by=sorted_by,
2304            buckets=buckets,
2305        )
2306
2307    def _parse_copy_property(self) -> t.Optional[exp.CopyGrantsProperty]:
2308        if not self._match_text_seq("GRANTS"):
2309            self._retreat(self._index - 1)
2310            return None
2311
2312        return self.expression(exp.CopyGrantsProperty)
2313
2314    def _parse_freespace(self) -> exp.FreespaceProperty:
2315        self._match(TokenType.EQ)
2316        return self.expression(
2317            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
2318        )
2319
2320    def _parse_mergeblockratio(
2321        self, no: bool = False, default: bool = False
2322    ) -> exp.MergeBlockRatioProperty:
2323        if self._match(TokenType.EQ):
2324            return self.expression(
2325                exp.MergeBlockRatioProperty,
2326                this=self._parse_number(),
2327                percent=self._match(TokenType.PERCENT),
2328            )
2329
2330        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
2331
2332    def _parse_datablocksize(
2333        self,
2334        default: t.Optional[bool] = None,
2335        minimum: t.Optional[bool] = None,
2336        maximum: t.Optional[bool] = None,
2337    ) -> exp.DataBlocksizeProperty:
2338        self._match(TokenType.EQ)
2339        size = self._parse_number()
2340
2341        units = None
2342        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
2343            units = self._prev.text
2344
2345        return self.expression(
2346            exp.DataBlocksizeProperty,
2347            size=size,
2348            units=units,
2349            default=default,
2350            minimum=minimum,
2351            maximum=maximum,
2352        )
2353
2354    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
2355        self._match(TokenType.EQ)
2356        always = self._match_text_seq("ALWAYS")
2357        manual = self._match_text_seq("MANUAL")
2358        never = self._match_text_seq("NEVER")
2359        default = self._match_text_seq("DEFAULT")
2360
2361        autotemp = None
2362        if self._match_text_seq("AUTOTEMP"):
2363            autotemp = self._parse_schema()
2364
2365        return self.expression(
2366            exp.BlockCompressionProperty,
2367            always=always,
2368            manual=manual,
2369            never=never,
2370            default=default,
2371            autotemp=autotemp,
2372        )
2373
2374    def _parse_withisolatedloading(self) -> t.Optional[exp.IsolatedLoadingProperty]:
2375        index = self._index
2376        no = self._match_text_seq("NO")
2377        concurrent = self._match_text_seq("CONCURRENT")
2378
2379        if not self._match_text_seq("ISOLATED", "LOADING"):
2380            self._retreat(index)
2381            return None
2382
2383        target = self._parse_var_from_options(self.ISOLATED_LOADING_OPTIONS, raise_unmatched=False)
2384        return self.expression(
2385            exp.IsolatedLoadingProperty, no=no, concurrent=concurrent, target=target
2386        )
2387
2388    def _parse_locking(self) -> exp.LockingProperty:
2389        if self._match(TokenType.TABLE):
2390            kind = "TABLE"
2391        elif self._match(TokenType.VIEW):
2392            kind = "VIEW"
2393        elif self._match(TokenType.ROW):
2394            kind = "ROW"
2395        elif self._match_text_seq("DATABASE"):
2396            kind = "DATABASE"
2397        else:
2398            kind = None
2399
2400        if kind in ("DATABASE", "TABLE", "VIEW"):
2401            this = self._parse_table_parts()
2402        else:
2403            this = None
2404
2405        if self._match(TokenType.FOR):
2406            for_or_in = "FOR"
2407        elif self._match(TokenType.IN):
2408            for_or_in = "IN"
2409        else:
2410            for_or_in = None
2411
2412        if self._match_text_seq("ACCESS"):
2413            lock_type = "ACCESS"
2414        elif self._match_texts(("EXCL", "EXCLUSIVE")):
2415            lock_type = "EXCLUSIVE"
2416        elif self._match_text_seq("SHARE"):
2417            lock_type = "SHARE"
2418        elif self._match_text_seq("READ"):
2419            lock_type = "READ"
2420        elif self._match_text_seq("WRITE"):
2421            lock_type = "WRITE"
2422        elif self._match_text_seq("CHECKSUM"):
2423            lock_type = "CHECKSUM"
2424        else:
2425            lock_type = None
2426
2427        override = self._match_text_seq("OVERRIDE")
2428
2429        return self.expression(
2430            exp.LockingProperty,
2431            this=this,
2432            kind=kind,
2433            for_or_in=for_or_in,
2434            lock_type=lock_type,
2435            override=override,
2436        )
2437
2438    def _parse_partition_by(self) -> t.List[exp.Expression]:
2439        if self._match(TokenType.PARTITION_BY):
2440            return self._parse_csv(self._parse_assignment)
2441        return []
2442
2443    def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
2444        def _parse_partition_bound_expr() -> t.Optional[exp.Expression]:
2445            if self._match_text_seq("MINVALUE"):
2446                return exp.var("MINVALUE")
2447            if self._match_text_seq("MAXVALUE"):
2448                return exp.var("MAXVALUE")
2449            return self._parse_bitwise()
2450
2451        this: t.Optional[exp.Expression | t.List[exp.Expression]] = None
2452        expression = None
2453        from_expressions = None
2454        to_expressions = None
2455
2456        if self._match(TokenType.IN):
2457            this = self._parse_wrapped_csv(self._parse_bitwise)
2458        elif self._match(TokenType.FROM):
2459            from_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
2460            self._match_text_seq("TO")
2461            to_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
2462        elif self._match_text_seq("WITH", "(", "MODULUS"):
2463            this = self._parse_number()
2464            self._match_text_seq(",", "REMAINDER")
2465            expression = self._parse_number()
2466            self._match_r_paren()
2467        else:
2468            self.raise_error("Failed to parse partition bound spec.")
2469
2470        return self.expression(
2471            exp.PartitionBoundSpec,
2472            this=this,
2473            expression=expression,
2474            from_expressions=from_expressions,
2475            to_expressions=to_expressions,
2476        )
2477
2478    # https://www.postgresql.org/docs/current/sql-createtable.html
2479    def _parse_partitioned_of(self) -> t.Optional[exp.PartitionedOfProperty]:
2480        if not self._match_text_seq("OF"):
2481            self._retreat(self._index - 1)
2482            return None
2483
2484        this = self._parse_table(schema=True)
2485
2486        if self._match(TokenType.DEFAULT):
2487            expression: exp.Var | exp.PartitionBoundSpec = exp.var("DEFAULT")
2488        elif self._match_text_seq("FOR", "VALUES"):
2489            expression = self._parse_partition_bound_spec()
2490        else:
2491            self.raise_error("Expecting either DEFAULT or FOR VALUES clause.")
2492
2493        return self.expression(exp.PartitionedOfProperty, this=this, expression=expression)
2494
2495    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
2496        self._match(TokenType.EQ)
2497        return self.expression(
2498            exp.PartitionedByProperty,
2499            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
2500        )
2501
2502    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
2503        if self._match_text_seq("AND", "STATISTICS"):
2504            statistics = True
2505        elif self._match_text_seq("AND", "NO", "STATISTICS"):
2506            statistics = False
2507        else:
2508            statistics = None
2509
2510        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
2511
2512    def _parse_contains_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2513        if self._match_text_seq("SQL"):
2514            return self.expression(exp.SqlReadWriteProperty, this="CONTAINS SQL")
2515        return None
2516
2517    def _parse_modifies_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2518        if self._match_text_seq("SQL", "DATA"):
2519            return self.expression(exp.SqlReadWriteProperty, this="MODIFIES SQL DATA")
2520        return None
2521
2522    def _parse_no_property(self) -> t.Optional[exp.Expression]:
2523        if self._match_text_seq("PRIMARY", "INDEX"):
2524            return exp.NoPrimaryIndexProperty()
2525        if self._match_text_seq("SQL"):
2526            return self.expression(exp.SqlReadWriteProperty, this="NO SQL")
2527        return None
2528
2529    def _parse_on_property(self) -> t.Optional[exp.Expression]:
2530        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
2531            return exp.OnCommitProperty()
2532        if self._match_text_seq("COMMIT", "DELETE", "ROWS"):
2533            return exp.OnCommitProperty(delete=True)
2534        return self.expression(exp.OnProperty, this=self._parse_schema(self._parse_id_var()))
2535
2536    def _parse_reads_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2537        if self._match_text_seq("SQL", "DATA"):
2538            return self.expression(exp.SqlReadWriteProperty, this="READS SQL DATA")
2539        return None
2540
2541    def _parse_distkey(self) -> exp.DistKeyProperty:
2542        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
2543
2544    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
2545        table = self._parse_table(schema=True)
2546
2547        options = []
2548        while self._match_texts(("INCLUDING", "EXCLUDING")):
2549            this = self._prev.text.upper()
2550
2551            id_var = self._parse_id_var()
2552            if not id_var:
2553                return None
2554
2555            options.append(
2556                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
2557            )
2558
2559        return self.expression(exp.LikeProperty, this=table, expressions=options)
2560
2561    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
2562        return self.expression(
2563            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
2564        )
2565
2566    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
2567        self._match(TokenType.EQ)
2568        return self.expression(
2569            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
2570        )
2571
2572    def _parse_remote_with_connection(self) -> exp.RemoteWithConnectionModelProperty:
2573        self._match_text_seq("WITH", "CONNECTION")
2574        return self.expression(
2575            exp.RemoteWithConnectionModelProperty, this=self._parse_table_parts()
2576        )
2577
2578    def _parse_returns(self) -> exp.ReturnsProperty:
2579        value: t.Optional[exp.Expression]
2580        null = None
2581        is_table = self._match(TokenType.TABLE)
2582
2583        if is_table:
2584            if self._match(TokenType.LT):
2585                value = self.expression(
2586                    exp.Schema,
2587                    this="TABLE",
2588                    expressions=self._parse_csv(self._parse_struct_types),
2589                )
2590                if not self._match(TokenType.GT):
2591                    self.raise_error("Expecting >")
2592            else:
2593                value = self._parse_schema(exp.var("TABLE"))
2594        elif self._match_text_seq("NULL", "ON", "NULL", "INPUT"):
2595            null = True
2596            value = None
2597        else:
2598            value = self._parse_types()
2599
2600        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table, null=null)
2601
2602    def _parse_describe(self) -> exp.Describe:
2603        kind = self._match_set(self.CREATABLES) and self._prev.text
2604        style = self._match_texts(self.DESCRIBE_STYLES) and self._prev.text.upper()
2605        if self._match(TokenType.DOT):
2606            style = None
2607            self._retreat(self._index - 2)
2608        this = self._parse_table(schema=True)
2609        properties = self._parse_properties()
2610        expressions = properties.expressions if properties else None
2611        partition = self._parse_partition()
2612        return self.expression(
2613            exp.Describe,
2614            this=this,
2615            style=style,
2616            kind=kind,
2617            expressions=expressions,
2618            partition=partition,
2619        )
2620
2621    def _parse_multitable_inserts(self, comments: t.Optional[t.List[str]]) -> exp.MultitableInserts:
2622        kind = self._prev.text.upper()
2623        expressions = []
2624
2625        def parse_conditional_insert() -> t.Optional[exp.ConditionalInsert]:
2626            if self._match(TokenType.WHEN):
2627                expression = self._parse_disjunction()
2628                self._match(TokenType.THEN)
2629            else:
2630                expression = None
2631
2632            else_ = self._match(TokenType.ELSE)
2633
2634            if not self._match(TokenType.INTO):
2635                return None
2636
2637            return self.expression(
2638                exp.ConditionalInsert,
2639                this=self.expression(
2640                    exp.Insert,
2641                    this=self._parse_table(schema=True),
2642                    expression=self._parse_derived_table_values(),
2643                ),
2644                expression=expression,
2645                else_=else_,
2646            )
2647
2648        expression = parse_conditional_insert()
2649        while expression is not None:
2650            expressions.append(expression)
2651            expression = parse_conditional_insert()
2652
2653        return self.expression(
2654            exp.MultitableInserts,
2655            kind=kind,
2656            comments=comments,
2657            expressions=expressions,
2658            source=self._parse_table(),
2659        )
2660
2661    def _parse_insert(self) -> t.Union[exp.Insert, exp.MultitableInserts]:
2662        comments = ensure_list(self._prev_comments)
2663        hint = self._parse_hint()
2664        overwrite = self._match(TokenType.OVERWRITE)
2665        ignore = self._match(TokenType.IGNORE)
2666        local = self._match_text_seq("LOCAL")
2667        alternative = None
2668        is_function = None
2669
2670        if self._match_text_seq("DIRECTORY"):
2671            this: t.Optional[exp.Expression] = self.expression(
2672                exp.Directory,
2673                this=self._parse_var_or_string(),
2674                local=local,
2675                row_format=self._parse_row_format(match_row=True),
2676            )
2677        else:
2678            if self._match_set((TokenType.FIRST, TokenType.ALL)):
2679                comments += ensure_list(self._prev_comments)
2680                return self._parse_multitable_inserts(comments)
2681
2682            if self._match(TokenType.OR):
2683                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
2684
2685            self._match(TokenType.INTO)
2686            comments += ensure_list(self._prev_comments)
2687            self._match(TokenType.TABLE)
2688            is_function = self._match(TokenType.FUNCTION)
2689
2690            this = (
2691                self._parse_table(schema=True, parse_partition=True)
2692                if not is_function
2693                else self._parse_function()
2694            )
2695
2696        returning = self._parse_returning()
2697
2698        return self.expression(
2699            exp.Insert,
2700            comments=comments,
2701            hint=hint,
2702            is_function=is_function,
2703            this=this,
2704            stored=self._match_text_seq("STORED") and self._parse_stored(),
2705            by_name=self._match_text_seq("BY", "NAME"),
2706            exists=self._parse_exists(),
2707            where=self._match_pair(TokenType.REPLACE, TokenType.WHERE) and self._parse_assignment(),
2708            partition=self._match(TokenType.PARTITION_BY) and self._parse_partitioned_by(),
2709            settings=self._match_text_seq("SETTINGS") and self._parse_settings_property(),
2710            expression=self._parse_derived_table_values() or self._parse_ddl_select(),
2711            conflict=self._parse_on_conflict(),
2712            returning=returning or self._parse_returning(),
2713            overwrite=overwrite,
2714            alternative=alternative,
2715            ignore=ignore,
2716            source=self._match(TokenType.TABLE) and self._parse_table(),
2717        )
2718
2719    def _parse_kill(self) -> exp.Kill:
2720        kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
2721
2722        return self.expression(
2723            exp.Kill,
2724            this=self._parse_primary(),
2725            kind=kind,
2726        )
2727
2728    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
2729        conflict = self._match_text_seq("ON", "CONFLICT")
2730        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
2731
2732        if not conflict and not duplicate:
2733            return None
2734
2735        conflict_keys = None
2736        constraint = None
2737
2738        if conflict:
2739            if self._match_text_seq("ON", "CONSTRAINT"):
2740                constraint = self._parse_id_var()
2741            elif self._match(TokenType.L_PAREN):
2742                conflict_keys = self._parse_csv(self._parse_id_var)
2743                self._match_r_paren()
2744
2745        action = self._parse_var_from_options(self.CONFLICT_ACTIONS)
2746        if self._prev.token_type == TokenType.UPDATE:
2747            self._match(TokenType.SET)
2748            expressions = self._parse_csv(self._parse_equality)
2749        else:
2750            expressions = None
2751
2752        return self.expression(
2753            exp.OnConflict,
2754            duplicate=duplicate,
2755            expressions=expressions,
2756            action=action,
2757            conflict_keys=conflict_keys,
2758            constraint=constraint,
2759        )
2760
2761    def _parse_returning(self) -> t.Optional[exp.Returning]:
2762        if not self._match(TokenType.RETURNING):
2763            return None
2764        return self.expression(
2765            exp.Returning,
2766            expressions=self._parse_csv(self._parse_expression),
2767            into=self._match(TokenType.INTO) and self._parse_table_part(),
2768        )
2769
2770    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2771        if not self._match(TokenType.FORMAT):
2772            return None
2773        return self._parse_row_format()
2774
2775    def _parse_serde_properties(self, with_: bool = False) -> t.Optional[exp.SerdeProperties]:
2776        index = self._index
2777        with_ = with_ or self._match_text_seq("WITH")
2778
2779        if not self._match(TokenType.SERDE_PROPERTIES):
2780            self._retreat(index)
2781            return None
2782        return self.expression(
2783            exp.SerdeProperties,
2784            **{  # type: ignore
2785                "expressions": self._parse_wrapped_properties(),
2786                "with": with_,
2787            },
2788        )
2789
2790    def _parse_row_format(
2791        self, match_row: bool = False
2792    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2793        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
2794            return None
2795
2796        if self._match_text_seq("SERDE"):
2797            this = self._parse_string()
2798
2799            serde_properties = self._parse_serde_properties()
2800
2801            return self.expression(
2802                exp.RowFormatSerdeProperty, this=this, serde_properties=serde_properties
2803            )
2804
2805        self._match_text_seq("DELIMITED")
2806
2807        kwargs = {}
2808
2809        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
2810            kwargs["fields"] = self._parse_string()
2811            if self._match_text_seq("ESCAPED", "BY"):
2812                kwargs["escaped"] = self._parse_string()
2813        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
2814            kwargs["collection_items"] = self._parse_string()
2815        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
2816            kwargs["map_keys"] = self._parse_string()
2817        if self._match_text_seq("LINES", "TERMINATED", "BY"):
2818            kwargs["lines"] = self._parse_string()
2819        if self._match_text_seq("NULL", "DEFINED", "AS"):
2820            kwargs["null"] = self._parse_string()
2821
2822        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
2823
2824    def _parse_load(self) -> exp.LoadData | exp.Command:
2825        if self._match_text_seq("DATA"):
2826            local = self._match_text_seq("LOCAL")
2827            self._match_text_seq("INPATH")
2828            inpath = self._parse_string()
2829            overwrite = self._match(TokenType.OVERWRITE)
2830            self._match_pair(TokenType.INTO, TokenType.TABLE)
2831
2832            return self.expression(
2833                exp.LoadData,
2834                this=self._parse_table(schema=True),
2835                local=local,
2836                overwrite=overwrite,
2837                inpath=inpath,
2838                partition=self._parse_partition(),
2839                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
2840                serde=self._match_text_seq("SERDE") and self._parse_string(),
2841            )
2842        return self._parse_as_command(self._prev)
2843
2844    def _parse_delete(self) -> exp.Delete:
2845        # This handles MySQL's "Multiple-Table Syntax"
2846        # https://dev.mysql.com/doc/refman/8.0/en/delete.html
2847        tables = None
2848        comments = self._prev_comments
2849        if not self._match(TokenType.FROM, advance=False):
2850            tables = self._parse_csv(self._parse_table) or None
2851
2852        returning = self._parse_returning()
2853
2854        return self.expression(
2855            exp.Delete,
2856            comments=comments,
2857            tables=tables,
2858            this=self._match(TokenType.FROM) and self._parse_table(joins=True),
2859            using=self._match(TokenType.USING) and self._parse_table(joins=True),
2860            cluster=self._match(TokenType.ON) and self._parse_on_property(),
2861            where=self._parse_where(),
2862            returning=returning or self._parse_returning(),
2863            limit=self._parse_limit(),
2864        )
2865
2866    def _parse_update(self) -> exp.Update:
2867        comments = self._prev_comments
2868        this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
2869        expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
2870        returning = self._parse_returning()
2871        return self.expression(
2872            exp.Update,
2873            comments=comments,
2874            **{  # type: ignore
2875                "this": this,
2876                "expressions": expressions,
2877                "from": self._parse_from(joins=True),
2878                "where": self._parse_where(),
2879                "returning": returning or self._parse_returning(),
2880                "order": self._parse_order(),
2881                "limit": self._parse_limit(),
2882            },
2883        )
2884
2885    def _parse_uncache(self) -> exp.Uncache:
2886        if not self._match(TokenType.TABLE):
2887            self.raise_error("Expecting TABLE after UNCACHE")
2888
2889        return self.expression(
2890            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
2891        )
2892
2893    def _parse_cache(self) -> exp.Cache:
2894        lazy = self._match_text_seq("LAZY")
2895        self._match(TokenType.TABLE)
2896        table = self._parse_table(schema=True)
2897
2898        options = []
2899        if self._match_text_seq("OPTIONS"):
2900            self._match_l_paren()
2901            k = self._parse_string()
2902            self._match(TokenType.EQ)
2903            v = self._parse_string()
2904            options = [k, v]
2905            self._match_r_paren()
2906
2907        self._match(TokenType.ALIAS)
2908        return self.expression(
2909            exp.Cache,
2910            this=table,
2911            lazy=lazy,
2912            options=options,
2913            expression=self._parse_select(nested=True),
2914        )
2915
2916    def _parse_partition(self) -> t.Optional[exp.Partition]:
2917        if not self._match(TokenType.PARTITION):
2918            return None
2919
2920        return self.expression(
2921            exp.Partition, expressions=self._parse_wrapped_csv(self._parse_assignment)
2922        )
2923
2924    def _parse_value(self) -> t.Optional[exp.Tuple]:
2925        if self._match(TokenType.L_PAREN):
2926            expressions = self._parse_csv(self._parse_expression)
2927            self._match_r_paren()
2928            return self.expression(exp.Tuple, expressions=expressions)
2929
2930        # In some dialects we can have VALUES 1, 2 which results in 1 column & 2 rows.
2931        expression = self._parse_expression()
2932        if expression:
2933            return self.expression(exp.Tuple, expressions=[expression])
2934        return None
2935
2936    def _parse_projections(self) -> t.List[exp.Expression]:
2937        return self._parse_expressions()
2938
2939    def _parse_select(
2940        self,
2941        nested: bool = False,
2942        table: bool = False,
2943        parse_subquery_alias: bool = True,
2944        parse_set_operation: bool = True,
2945    ) -> t.Optional[exp.Expression]:
2946        cte = self._parse_with()
2947
2948        if cte:
2949            this = self._parse_statement()
2950
2951            if not this:
2952                self.raise_error("Failed to parse any statement following CTE")
2953                return cte
2954
2955            if "with" in this.arg_types:
2956                this.set("with", cte)
2957            else:
2958                self.raise_error(f"{this.key} does not support CTE")
2959                this = cte
2960
2961            return this
2962
2963        # duckdb supports leading with FROM x
2964        from_ = self._parse_from() if self._match(TokenType.FROM, advance=False) else None
2965
2966        if self._match(TokenType.SELECT):
2967            comments = self._prev_comments
2968
2969            hint = self._parse_hint()
2970
2971            if self._next and not self._next.token_type == TokenType.DOT:
2972                all_ = self._match(TokenType.ALL)
2973                distinct = self._match_set(self.DISTINCT_TOKENS)
2974            else:
2975                all_, distinct = None, None
2976
2977            kind = (
2978                self._match(TokenType.ALIAS)
2979                and self._match_texts(("STRUCT", "VALUE"))
2980                and self._prev.text.upper()
2981            )
2982
2983            if distinct:
2984                distinct = self.expression(
2985                    exp.Distinct,
2986                    on=self._parse_value() if self._match(TokenType.ON) else None,
2987                )
2988
2989            if all_ and distinct:
2990                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
2991
2992            operation_modifiers = []
2993            while self._curr and self._match_texts(self.OPERATION_MODIFIERS):
2994                operation_modifiers.append(exp.var(self._prev.text.upper()))
2995
2996            limit = self._parse_limit(top=True)
2997            projections = self._parse_projections()
2998
2999            this = self.expression(
3000                exp.Select,
3001                kind=kind,
3002                hint=hint,
3003                distinct=distinct,
3004                expressions=projections,
3005                limit=limit,
3006                operation_modifiers=operation_modifiers or None,
3007            )
3008            this.comments = comments
3009
3010            into = self._parse_into()
3011            if into:
3012                this.set("into", into)
3013
3014            if not from_:
3015                from_ = self._parse_from()
3016
3017            if from_:
3018                this.set("from", from_)
3019
3020            this = self._parse_query_modifiers(this)
3021        elif (table or nested) and self._match(TokenType.L_PAREN):
3022            if self._match(TokenType.PIVOT):
3023                this = self._parse_simplified_pivot()
3024            elif self._match(TokenType.FROM):
3025                this = exp.select("*").from_(
3026                    t.cast(exp.From, self._parse_from(skip_from_token=True))
3027                )
3028            else:
3029                this = (
3030                    self._parse_table()
3031                    if table
3032                    else self._parse_select(nested=True, parse_set_operation=False)
3033                )
3034
3035                # Transform exp.Values into a exp.Table to pass through parse_query_modifiers
3036                # in case a modifier (e.g. join) is following
3037                if table and isinstance(this, exp.Values) and this.alias:
3038                    alias = this.args["alias"].pop()
3039                    this = exp.Table(this=this, alias=alias)
3040
3041                this = self._parse_query_modifiers(self._parse_set_operations(this))
3042
3043            self._match_r_paren()
3044
3045            # We return early here so that the UNION isn't attached to the subquery by the
3046            # following call to _parse_set_operations, but instead becomes the parent node
3047            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
3048        elif self._match(TokenType.VALUES, advance=False):
3049            this = self._parse_derived_table_values()
3050        elif from_:
3051            this = exp.select("*").from_(from_.this, copy=False)
3052        elif self._match(TokenType.SUMMARIZE):
3053            table = self._match(TokenType.TABLE)
3054            this = self._parse_select() or self._parse_string() or self._parse_table()
3055            return self.expression(exp.Summarize, this=this, table=table)
3056        elif self._match(TokenType.DESCRIBE):
3057            this = self._parse_describe()
3058        elif self._match_text_seq("STREAM"):
3059            this = self._parse_function()
3060            if this:
3061                this = self.expression(exp.Stream, this=this)
3062            else:
3063                self._retreat(self._index - 1)
3064        else:
3065            this = None
3066
3067        return self._parse_set_operations(this) if parse_set_operation else this
3068
3069    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
3070        if not skip_with_token and not self._match(TokenType.WITH):
3071            return None
3072
3073        comments = self._prev_comments
3074        recursive = self._match(TokenType.RECURSIVE)
3075
3076        last_comments = None
3077        expressions = []
3078        while True:
3079            expressions.append(self._parse_cte())
3080            if last_comments:
3081                expressions[-1].add_comments(last_comments)
3082
3083            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
3084                break
3085            else:
3086                self._match(TokenType.WITH)
3087
3088            last_comments = self._prev_comments
3089
3090        return self.expression(
3091            exp.With, comments=comments, expressions=expressions, recursive=recursive
3092        )
3093
3094    def _parse_cte(self) -> exp.CTE:
3095        alias = self._parse_table_alias(self.ID_VAR_TOKENS)
3096        if not alias or not alias.this:
3097            self.raise_error("Expected CTE to have alias")
3098
3099        self._match(TokenType.ALIAS)
3100        comments = self._prev_comments
3101
3102        if self._match_text_seq("NOT", "MATERIALIZED"):
3103            materialized = False
3104        elif self._match_text_seq("MATERIALIZED"):
3105            materialized = True
3106        else:
3107            materialized = None
3108
3109        return self.expression(
3110            exp.CTE,
3111            this=self._parse_wrapped(self._parse_statement),
3112            alias=alias,
3113            materialized=materialized,
3114            comments=comments,
3115        )
3116
3117    def _parse_table_alias(
3118        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
3119    ) -> t.Optional[exp.TableAlias]:
3120        any_token = self._match(TokenType.ALIAS)
3121        alias = (
3122            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
3123            or self._parse_string_as_identifier()
3124        )
3125
3126        index = self._index
3127        if self._match(TokenType.L_PAREN):
3128            columns = self._parse_csv(self._parse_function_parameter)
3129            self._match_r_paren() if columns else self._retreat(index)
3130        else:
3131            columns = None
3132
3133        if not alias and not columns:
3134            return None
3135
3136        table_alias = self.expression(exp.TableAlias, this=alias, columns=columns)
3137
3138        # We bubble up comments from the Identifier to the TableAlias
3139        if isinstance(alias, exp.Identifier):
3140            table_alias.add_comments(alias.pop_comments())
3141
3142        return table_alias
3143
3144    def _parse_subquery(
3145        self, this: t.Optional[exp.Expression], parse_alias: bool = True
3146    ) -> t.Optional[exp.Subquery]:
3147        if not this:
3148            return None
3149
3150        return self.expression(
3151            exp.Subquery,
3152            this=this,
3153            pivots=self._parse_pivots(),
3154            alias=self._parse_table_alias() if parse_alias else None,
3155            sample=self._parse_table_sample(),
3156        )
3157
3158    def _implicit_unnests_to_explicit(self, this: E) -> E:
3159        from sqlglot.optimizer.normalize_identifiers import normalize_identifiers as _norm
3160
3161        refs = {_norm(this.args["from"].this.copy(), dialect=self.dialect).alias_or_name}
3162        for i, join in enumerate(this.args.get("joins") or []):
3163            table = join.this
3164            normalized_table = table.copy()
3165            normalized_table.meta["maybe_column"] = True
3166            normalized_table = _norm(normalized_table, dialect=self.dialect)
3167
3168            if isinstance(table, exp.Table) and not join.args.get("on"):
3169                if normalized_table.parts[0].name in refs:
3170                    table_as_column = table.to_column()
3171                    unnest = exp.Unnest(expressions=[table_as_column])
3172
3173                    # Table.to_column creates a parent Alias node that we want to convert to
3174                    # a TableAlias and attach to the Unnest, so it matches the parser's output
3175                    if isinstance(table.args.get("alias"), exp.TableAlias):
3176                        table_as_column.replace(table_as_column.this)
3177                        exp.alias_(unnest, None, table=[table.args["alias"].this], copy=False)
3178
3179                    table.replace(unnest)
3180
3181            refs.add(normalized_table.alias_or_name)
3182
3183        return this
3184
3185    def _parse_query_modifiers(
3186        self, this: t.Optional[exp.Expression]
3187    ) -> t.Optional[exp.Expression]:
3188        if isinstance(this, (exp.Query, exp.Table)):
3189            for join in self._parse_joins():
3190                this.append("joins", join)
3191            for lateral in iter(self._parse_lateral, None):
3192                this.append("laterals", lateral)
3193
3194            while True:
3195                if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
3196                    parser = self.QUERY_MODIFIER_PARSERS[self._curr.token_type]
3197                    key, expression = parser(self)
3198
3199                    if expression:
3200                        this.set(key, expression)
3201                        if key == "limit":
3202                            offset = expression.args.pop("offset", None)
3203
3204                            if offset:
3205                                offset = exp.Offset(expression=offset)
3206                                this.set("offset", offset)
3207
3208                                limit_by_expressions = expression.expressions
3209                                expression.set("expressions", None)
3210                                offset.set("expressions", limit_by_expressions)
3211                        continue
3212                break
3213
3214        if self.SUPPORTS_IMPLICIT_UNNEST and this and this.args.get("from"):
3215            this = self._implicit_unnests_to_explicit(this)
3216
3217        return this
3218
3219    def _parse_hint(self) -> t.Optional[exp.Hint]:
3220        if self._match(TokenType.HINT):
3221            hints = []
3222            for hint in iter(
3223                lambda: self._parse_csv(
3224                    lambda: self._parse_function() or self._parse_var(upper=True)
3225                ),
3226                [],
3227            ):
3228                hints.extend(hint)
3229
3230            if not self._match_pair(TokenType.STAR, TokenType.SLASH):
3231                self.raise_error("Expected */ after HINT")
3232
3233            return self.expression(exp.Hint, expressions=hints)
3234
3235        return None
3236
3237    def _parse_into(self) -> t.Optional[exp.Into]:
3238        if not self._match(TokenType.INTO):
3239            return None
3240
3241        temp = self._match(TokenType.TEMPORARY)
3242        unlogged = self._match_text_seq("UNLOGGED")
3243        self._match(TokenType.TABLE)
3244
3245        return self.expression(
3246            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
3247        )
3248
3249    def _parse_from(
3250        self, joins: bool = False, skip_from_token: bool = False
3251    ) -> t.Optional[exp.From]:
3252        if not skip_from_token and not self._match(TokenType.FROM):
3253            return None
3254
3255        return self.expression(
3256            exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
3257        )
3258
3259    def _parse_match_recognize_measure(self) -> exp.MatchRecognizeMeasure:
3260        return self.expression(
3261            exp.MatchRecognizeMeasure,
3262            window_frame=self._match_texts(("FINAL", "RUNNING")) and self._prev.text.upper(),
3263            this=self._parse_expression(),
3264        )
3265
3266    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
3267        if not self._match(TokenType.MATCH_RECOGNIZE):
3268            return None
3269
3270        self._match_l_paren()
3271
3272        partition = self._parse_partition_by()
3273        order = self._parse_order()
3274
3275        measures = (
3276            self._parse_csv(self._parse_match_recognize_measure)
3277            if self._match_text_seq("MEASURES")
3278            else None
3279        )
3280
3281        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
3282            rows = exp.var("ONE ROW PER MATCH")
3283        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
3284            text = "ALL ROWS PER MATCH"
3285            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
3286                text += " SHOW EMPTY MATCHES"
3287            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
3288                text += " OMIT EMPTY MATCHES"
3289            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
3290                text += " WITH UNMATCHED ROWS"
3291            rows = exp.var(text)
3292        else:
3293            rows = None
3294
3295        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
3296            text = "AFTER MATCH SKIP"
3297            if self._match_text_seq("PAST", "LAST", "ROW"):
3298                text += " PAST LAST ROW"
3299            elif self._match_text_seq("TO", "NEXT", "ROW"):
3300                text += " TO NEXT ROW"
3301            elif self._match_text_seq("TO", "FIRST"):
3302                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
3303            elif self._match_text_seq("TO", "LAST"):
3304                text += f" TO LAST {self._advance_any().text}"  # type: ignore
3305            after = exp.var(text)
3306        else:
3307            after = None
3308
3309        if self._match_text_seq("PATTERN"):
3310            self._match_l_paren()
3311
3312            if not self._curr:
3313                self.raise_error("Expecting )", self._curr)
3314
3315            paren = 1
3316            start = self._curr
3317
3318            while self._curr and paren > 0:
3319                if self._curr.token_type == TokenType.L_PAREN:
3320                    paren += 1
3321                if self._curr.token_type == TokenType.R_PAREN:
3322                    paren -= 1
3323
3324                end = self._prev
3325                self._advance()
3326
3327            if paren > 0:
3328                self.raise_error("Expecting )", self._curr)
3329
3330            pattern = exp.var(self._find_sql(start, end))
3331        else:
3332            pattern = None
3333
3334        define = (
3335            self._parse_csv(self._parse_name_as_expression)
3336            if self._match_text_seq("DEFINE")
3337            else None
3338        )
3339
3340        self._match_r_paren()
3341
3342        return self.expression(
3343            exp.MatchRecognize,
3344            partition_by=partition,
3345            order=order,
3346            measures=measures,
3347            rows=rows,
3348            after=after,
3349            pattern=pattern,
3350            define=define,
3351            alias=self._parse_table_alias(),
3352        )
3353
3354    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
3355        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
3356        if not cross_apply and self._match_pair(TokenType.OUTER, TokenType.APPLY):
3357            cross_apply = False
3358
3359        if cross_apply is not None:
3360            this = self._parse_select(table=True)
3361            view = None
3362            outer = None
3363        elif self._match(TokenType.LATERAL):
3364            this = self._parse_select(table=True)
3365            view = self._match(TokenType.VIEW)
3366            outer = self._match(TokenType.OUTER)
3367        else:
3368            return None
3369
3370        if not this:
3371            this = (
3372                self._parse_unnest()
3373                or self._parse_function()
3374                or self._parse_id_var(any_token=False)
3375            )
3376
3377            while self._match(TokenType.DOT):
3378                this = exp.Dot(
3379                    this=this,
3380                    expression=self._parse_function() or self._parse_id_var(any_token=False),
3381                )
3382
3383        if view:
3384            table = self._parse_id_var(any_token=False)
3385            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
3386            table_alias: t.Optional[exp.TableAlias] = self.expression(
3387                exp.TableAlias, this=table, columns=columns
3388            )
3389        elif isinstance(this, (exp.Subquery, exp.Unnest)) and this.alias:
3390            # We move the alias from the lateral's child node to the lateral itself
3391            table_alias = this.args["alias"].pop()
3392        else:
3393            table_alias = self._parse_table_alias()
3394
3395        return self.expression(
3396            exp.Lateral,
3397            this=this,
3398            view=view,
3399            outer=outer,
3400            alias=table_alias,
3401            cross_apply=cross_apply,
3402        )
3403
3404    def _parse_join_parts(
3405        self,
3406    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
3407        return (
3408            self._match_set(self.JOIN_METHODS) and self._prev,
3409            self._match_set(self.JOIN_SIDES) and self._prev,
3410            self._match_set(self.JOIN_KINDS) and self._prev,
3411        )
3412
3413    def _parse_using_identifiers(self) -> t.List[exp.Expression]:
3414        def _parse_column_as_identifier() -> t.Optional[exp.Expression]:
3415            this = self._parse_column()
3416            if isinstance(this, exp.Column):
3417                return this.this
3418            return this
3419
3420        return self._parse_wrapped_csv(_parse_column_as_identifier, optional=True)
3421
3422    def _parse_join(
3423        self, skip_join_token: bool = False, parse_bracket: bool = False
3424    ) -> t.Optional[exp.Join]:
3425        if self._match(TokenType.COMMA):
3426            return self.expression(exp.Join, this=self._parse_table())
3427
3428        index = self._index
3429        method, side, kind = self._parse_join_parts()
3430        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
3431        join = self._match(TokenType.JOIN) or (kind and kind.token_type == TokenType.STRAIGHT_JOIN)
3432
3433        if not skip_join_token and not join:
3434            self._retreat(index)
3435            kind = None
3436            method = None
3437            side = None
3438
3439        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
3440        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
3441
3442        if not skip_join_token and not join and not outer_apply and not cross_apply:
3443            return None
3444
3445        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table(parse_bracket=parse_bracket)}
3446        if kind and kind.token_type == TokenType.ARRAY and self._match(TokenType.COMMA):
3447            kwargs["expressions"] = self._parse_csv(
3448                lambda: self._parse_table(parse_bracket=parse_bracket)
3449            )
3450
3451        if method:
3452            kwargs["method"] = method.text
3453        if side:
3454            kwargs["side"] = side.text
3455        if kind:
3456            kwargs["kind"] = kind.text
3457        if hint:
3458            kwargs["hint"] = hint
3459
3460        if self._match(TokenType.MATCH_CONDITION):
3461            kwargs["match_condition"] = self._parse_wrapped(self._parse_comparison)
3462
3463        if self._match(TokenType.ON):
3464            kwargs["on"] = self._parse_assignment()
3465        elif self._match(TokenType.USING):
3466            kwargs["using"] = self._parse_using_identifiers()
3467        elif (
3468            not (outer_apply or cross_apply)
3469            and not isinstance(kwargs["this"], exp.Unnest)
3470            and not (kind and kind.token_type in (TokenType.CROSS, TokenType.ARRAY))
3471        ):
3472            index = self._index
3473            joins: t.Optional[list] = list(self._parse_joins())
3474
3475            if joins and self._match(TokenType.ON):
3476                kwargs["on"] = self._parse_assignment()
3477            elif joins and self._match(TokenType.USING):
3478                kwargs["using"] = self._parse_using_identifiers()
3479            else:
3480                joins = None
3481                self._retreat(index)
3482
3483            kwargs["this"].set("joins", joins if joins else None)
3484
3485        comments = [c for token in (method, side, kind) if token for c in token.comments]
3486        return self.expression(exp.Join, comments=comments, **kwargs)
3487
3488    def _parse_opclass(self) -> t.Optional[exp.Expression]:
3489        this = self._parse_assignment()
3490
3491        if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
3492            return this
3493
3494        if not self._match_set(self.OPTYPE_FOLLOW_TOKENS, advance=False):
3495            return self.expression(exp.Opclass, this=this, expression=self._parse_table_parts())
3496
3497        return this
3498
3499    def _parse_index_params(self) -> exp.IndexParameters:
3500        using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
3501
3502        if self._match(TokenType.L_PAREN, advance=False):
3503            columns = self._parse_wrapped_csv(self._parse_with_operator)
3504        else:
3505            columns = None
3506
3507        include = self._parse_wrapped_id_vars() if self._match_text_seq("INCLUDE") else None
3508        partition_by = self._parse_partition_by()
3509        with_storage = self._match(TokenType.WITH) and self._parse_wrapped_properties()
3510        tablespace = (
3511            self._parse_var(any_token=True)
3512            if self._match_text_seq("USING", "INDEX", "TABLESPACE")
3513            else None
3514        )
3515        where = self._parse_where()
3516
3517        on = self._parse_field() if self._match(TokenType.ON) else None
3518
3519        return self.expression(
3520            exp.IndexParameters,
3521            using=using,
3522            columns=columns,
3523            include=include,
3524            partition_by=partition_by,
3525            where=where,
3526            with_storage=with_storage,
3527            tablespace=tablespace,
3528            on=on,
3529        )
3530
3531    def _parse_index(
3532        self, index: t.Optional[exp.Expression] = None, anonymous: bool = False
3533    ) -> t.Optional[exp.Index]:
3534        if index or anonymous:
3535            unique = None
3536            primary = None
3537            amp = None
3538
3539            self._match(TokenType.ON)
3540            self._match(TokenType.TABLE)  # hive
3541            table = self._parse_table_parts(schema=True)
3542        else:
3543            unique = self._match(TokenType.UNIQUE)
3544            primary = self._match_text_seq("PRIMARY")
3545            amp = self._match_text_seq("AMP")
3546
3547            if not self._match(TokenType.INDEX):
3548                return None
3549
3550            index = self._parse_id_var()
3551            table = None
3552
3553        params = self._parse_index_params()
3554
3555        return self.expression(
3556            exp.Index,
3557            this=index,
3558            table=table,
3559            unique=unique,
3560            primary=primary,
3561            amp=amp,
3562            params=params,
3563        )
3564
3565    def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
3566        hints: t.List[exp.Expression] = []
3567        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
3568            # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
3569            hints.append(
3570                self.expression(
3571                    exp.WithTableHint,
3572                    expressions=self._parse_csv(
3573                        lambda: self._parse_function() or self._parse_var(any_token=True)
3574                    ),
3575                )
3576            )
3577            self._match_r_paren()
3578        else:
3579            # https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
3580            while self._match_set(self.TABLE_INDEX_HINT_TOKENS):
3581                hint = exp.IndexTableHint(this=self._prev.text.upper())
3582
3583                self._match_set((TokenType.INDEX, TokenType.KEY))
3584                if self._match(TokenType.FOR):
3585                    hint.set("target", self._advance_any() and self._prev.text.upper())
3586
3587                hint.set("expressions", self._parse_wrapped_id_vars())
3588                hints.append(hint)
3589
3590        return hints or None
3591
3592    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
3593        return (
3594            (not schema and self._parse_function(optional_parens=False))
3595            or self._parse_id_var(any_token=False)
3596            or self._parse_string_as_identifier()
3597            or self._parse_placeholder()
3598        )
3599
3600    def _parse_table_parts(
3601        self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
3602    ) -> exp.Table:
3603        catalog = None
3604        db = None
3605        table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
3606
3607        while self._match(TokenType.DOT):
3608            if catalog:
3609                # This allows nesting the table in arbitrarily many dot expressions if needed
3610                table = self.expression(
3611                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
3612                )
3613            else:
3614                catalog = db
3615                db = table
3616                # "" used for tsql FROM a..b case
3617                table = self._parse_table_part(schema=schema) or ""
3618
3619        if (
3620            wildcard
3621            and self._is_connected()
3622            and (isinstance(table, exp.Identifier) or not table)
3623            and self._match(TokenType.STAR)
3624        ):
3625            if isinstance(table, exp.Identifier):
3626                table.args["this"] += "*"
3627            else:
3628                table = exp.Identifier(this="*")
3629
3630        # We bubble up comments from the Identifier to the Table
3631        comments = table.pop_comments() if isinstance(table, exp.Expression) else None
3632
3633        if is_db_reference:
3634            catalog = db
3635            db = table
3636            table = None
3637
3638        if not table and not is_db_reference:
3639            self.raise_error(f"Expected table name but got {self._curr}")
3640        if not db and is_db_reference:
3641            self.raise_error(f"Expected database name but got {self._curr}")
3642
3643        table = self.expression(
3644            exp.Table,
3645            comments=comments,
3646            this=table,
3647            db=db,
3648            catalog=catalog,
3649        )
3650
3651        changes = self._parse_changes()
3652        if changes:
3653            table.set("changes", changes)
3654
3655        at_before = self._parse_historical_data()
3656        if at_before:
3657            table.set("when", at_before)
3658
3659        pivots = self._parse_pivots()
3660        if pivots:
3661            table.set("pivots", pivots)
3662
3663        return table
3664
3665    def _parse_table(
3666        self,
3667        schema: bool = False,
3668        joins: bool = False,
3669        alias_tokens: t.Optional[t.Collection[TokenType]] = None,
3670        parse_bracket: bool = False,
3671        is_db_reference: bool = False,
3672        parse_partition: bool = False,
3673    ) -> t.Optional[exp.Expression]:
3674        lateral = self._parse_lateral()
3675        if lateral:
3676            return lateral
3677
3678        unnest = self._parse_unnest()
3679        if unnest:
3680            return unnest
3681
3682        values = self._parse_derived_table_values()
3683        if values:
3684            return values
3685
3686        subquery = self._parse_select(table=True)
3687        if subquery:
3688            if not subquery.args.get("pivots"):
3689                subquery.set("pivots", self._parse_pivots())
3690            return subquery
3691
3692        bracket = parse_bracket and self._parse_bracket(None)
3693        bracket = self.expression(exp.Table, this=bracket) if bracket else None
3694
3695        rows_from = self._match_text_seq("ROWS", "FROM") and self._parse_wrapped_csv(
3696            self._parse_table
3697        )
3698        rows_from = self.expression(exp.Table, rows_from=rows_from) if rows_from else None
3699
3700        only = self._match(TokenType.ONLY)
3701
3702        this = t.cast(
3703            exp.Expression,
3704            bracket
3705            or rows_from
3706            or self._parse_bracket(
3707                self._parse_table_parts(schema=schema, is_db_reference=is_db_reference)
3708            ),
3709        )
3710
3711        if only:
3712            this.set("only", only)
3713
3714        # Postgres supports a wildcard (table) suffix operator, which is a no-op in this context
3715        self._match_text_seq("*")
3716
3717        parse_partition = parse_partition or self.SUPPORTS_PARTITION_SELECTION
3718        if parse_partition and self._match(TokenType.PARTITION, advance=False):
3719            this.set("partition", self._parse_partition())
3720
3721        if schema:
3722            return self._parse_schema(this=this)
3723
3724        version = self._parse_version()
3725
3726        if version:
3727            this.set("version", version)
3728
3729        if self.dialect.ALIAS_POST_TABLESAMPLE:
3730            this.set("sample", self._parse_table_sample())
3731
3732        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
3733        if alias:
3734            this.set("alias", alias)
3735
3736        if isinstance(this, exp.Table) and self._match_text_seq("AT"):
3737            return self.expression(
3738                exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
3739            )
3740
3741        this.set("hints", self._parse_table_hints())
3742
3743        if not this.args.get("pivots"):
3744            this.set("pivots", self._parse_pivots())
3745
3746        if not self.dialect.ALIAS_POST_TABLESAMPLE:
3747            this.set("sample", self._parse_table_sample())
3748
3749        if joins:
3750            for join in self._parse_joins():
3751                this.append("joins", join)
3752
3753        if self._match_pair(TokenType.WITH, TokenType.ORDINALITY):
3754            this.set("ordinality", True)
3755            this.set("alias", self._parse_table_alias())
3756
3757        return this
3758
3759    def _parse_version(self) -> t.Optional[exp.Version]:
3760        if self._match(TokenType.TIMESTAMP_SNAPSHOT):
3761            this = "TIMESTAMP"
3762        elif self._match(TokenType.VERSION_SNAPSHOT):
3763            this = "VERSION"
3764        else:
3765            return None
3766
3767        if self._match_set((TokenType.FROM, TokenType.BETWEEN)):
3768            kind = self._prev.text.upper()
3769            start = self._parse_bitwise()
3770            self._match_texts(("TO", "AND"))
3771            end = self._parse_bitwise()
3772            expression: t.Optional[exp.Expression] = self.expression(
3773                exp.Tuple, expressions=[start, end]
3774            )
3775        elif self._match_text_seq("CONTAINED", "IN"):
3776            kind = "CONTAINED IN"
3777            expression = self.expression(
3778                exp.Tuple, expressions=self._parse_wrapped_csv(self._parse_bitwise)
3779            )
3780        elif self._match(TokenType.ALL):
3781            kind = "ALL"
3782            expression = None
3783        else:
3784            self._match_text_seq("AS", "OF")
3785            kind = "AS OF"
3786            expression = self._parse_type()
3787
3788        return self.expression(exp.Version, this=this, expression=expression, kind=kind)
3789
3790    def _parse_historical_data(self) -> t.Optional[exp.HistoricalData]:
3791        # https://docs.snowflake.com/en/sql-reference/constructs/at-before
3792        index = self._index
3793        historical_data = None
3794        if self._match_texts(self.HISTORICAL_DATA_PREFIX):
3795            this = self._prev.text.upper()
3796            kind = (
3797                self._match(TokenType.L_PAREN)
3798                and self._match_texts(self.HISTORICAL_DATA_KIND)
3799                and self._prev.text.upper()
3800            )
3801            expression = self._match(TokenType.FARROW) and self._parse_bitwise()
3802
3803            if expression:
3804                self._match_r_paren()
3805                historical_data = self.expression(
3806                    exp.HistoricalData, this=this, kind=kind, expression=expression
3807                )
3808            else:
3809                self._retreat(index)
3810
3811        return historical_data
3812
3813    def _parse_changes(self) -> t.Optional[exp.Changes]:
3814        if not self._match_text_seq("CHANGES", "(", "INFORMATION", "=>"):
3815            return None
3816
3817        information = self._parse_var(any_token=True)
3818        self._match_r_paren()
3819
3820        return self.expression(
3821            exp.Changes,
3822            information=information,
3823            at_before=self._parse_historical_data(),
3824            end=self._parse_historical_data(),
3825        )
3826
3827    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
3828        if not self._match(TokenType.UNNEST):
3829            return None
3830
3831        expressions = self._parse_wrapped_csv(self._parse_equality)
3832        offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
3833
3834        alias = self._parse_table_alias() if with_alias else None
3835
3836        if alias:
3837            if self.dialect.UNNEST_COLUMN_ONLY:
3838                if alias.args.get("columns"):
3839                    self.raise_error("Unexpected extra column alias in unnest.")
3840
3841                alias.set("columns", [alias.this])
3842                alias.set("this", None)
3843
3844            columns = alias.args.get("columns") or []
3845            if offset and len(expressions) < len(columns):
3846                offset = columns.pop()
3847
3848        if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
3849            self._match(TokenType.ALIAS)
3850            offset = self._parse_id_var(
3851                any_token=False, tokens=self.UNNEST_OFFSET_ALIAS_TOKENS
3852            ) or exp.to_identifier("offset")
3853
3854        return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
3855
3856    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
3857        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
3858        if not is_derived and not (
3859            # ClickHouse's `FORMAT Values` is equivalent to `VALUES`
3860            self._match_text_seq("VALUES") or self._match_text_seq("FORMAT", "VALUES")
3861        ):
3862            return None
3863
3864        expressions = self._parse_csv(self._parse_value)
3865        alias = self._parse_table_alias()
3866
3867        if is_derived:
3868            self._match_r_paren()
3869
3870        return self.expression(
3871            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
3872        )
3873
3874    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
3875        if not self._match(TokenType.TABLE_SAMPLE) and not (
3876            as_modifier and self._match_text_seq("USING", "SAMPLE")
3877        ):
3878            return None
3879
3880        bucket_numerator = None
3881        bucket_denominator = None
3882        bucket_field = None
3883        percent = None
3884        size = None
3885        seed = None
3886
3887        method = self._parse_var(tokens=(TokenType.ROW,), upper=True)
3888        matched_l_paren = self._match(TokenType.L_PAREN)
3889
3890        if self.TABLESAMPLE_CSV:
3891            num = None
3892            expressions = self._parse_csv(self._parse_primary)
3893        else:
3894            expressions = None
3895            num = (
3896                self._parse_factor()
3897                if self._match(TokenType.NUMBER, advance=False)
3898                else self._parse_primary() or self._parse_placeholder()
3899            )
3900
3901        if self._match_text_seq("BUCKET"):
3902            bucket_numerator = self._parse_number()
3903            self._match_text_seq("OUT", "OF")
3904            bucket_denominator = bucket_denominator = self._parse_number()
3905            self._match(TokenType.ON)
3906            bucket_field = self._parse_field()
3907        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
3908            percent = num
3909        elif self._match(TokenType.ROWS) or not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
3910            size = num
3911        else:
3912            percent = num
3913
3914        if matched_l_paren:
3915            self._match_r_paren()
3916
3917        if self._match(TokenType.L_PAREN):
3918            method = self._parse_var(upper=True)
3919            seed = self._match(TokenType.COMMA) and self._parse_number()
3920            self._match_r_paren()
3921        elif self._match_texts(("SEED", "REPEATABLE")):
3922            seed = self._parse_wrapped(self._parse_number)
3923
3924        if not method and self.DEFAULT_SAMPLING_METHOD:
3925            method = exp.var(self.DEFAULT_SAMPLING_METHOD)
3926
3927        return self.expression(
3928            exp.TableSample,
3929            expressions=expressions,
3930            method=method,
3931            bucket_numerator=bucket_numerator,
3932            bucket_denominator=bucket_denominator,
3933            bucket_field=bucket_field,
3934            percent=percent,
3935            size=size,
3936            seed=seed,
3937        )
3938
3939    def _parse_pivots(self) -> t.Optional[t.List[exp.Pivot]]:
3940        return list(iter(self._parse_pivot, None)) or None
3941
3942    def _parse_joins(self) -> t.Iterator[exp.Join]:
3943        return iter(self._parse_join, None)
3944
3945    # https://duckdb.org/docs/sql/statements/pivot
3946    def _parse_simplified_pivot(self) -> exp.Pivot:
3947        def _parse_on() -> t.Optional[exp.Expression]:
3948            this = self._parse_bitwise()
3949            return self._parse_in(this) if self._match(TokenType.IN) else this
3950
3951        this = self._parse_table()
3952        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
3953        using = self._match(TokenType.USING) and self._parse_csv(
3954            lambda: self._parse_alias(self._parse_function())
3955        )
3956        group = self._parse_group()
3957        return self.expression(
3958            exp.Pivot, this=this, expressions=expressions, using=using, group=group
3959        )
3960
3961    def _parse_pivot_in(self) -> exp.In | exp.PivotAny:
3962        def _parse_aliased_expression() -> t.Optional[exp.Expression]:
3963            this = self._parse_select_or_expression()
3964
3965            self._match(TokenType.ALIAS)
3966            alias = self._parse_bitwise()
3967            if alias:
3968                if isinstance(alias, exp.Column) and not alias.db:
3969                    alias = alias.this
3970                return self.expression(exp.PivotAlias, this=this, alias=alias)
3971
3972            return this
3973
3974        value = self._parse_column()
3975
3976        if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
3977            self.raise_error("Expecting IN (")
3978
3979        if self._match(TokenType.ANY):
3980            exprs: t.List[exp.Expression] = ensure_list(exp.PivotAny(this=self._parse_order()))
3981        else:
3982            exprs = self._parse_csv(_parse_aliased_expression)
3983
3984        self._match_r_paren()
3985        return self.expression(exp.In, this=value, expressions=exprs)
3986
3987    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
3988        index = self._index
3989        include_nulls = None
3990
3991        if self._match(TokenType.PIVOT):
3992            unpivot = False
3993        elif self._match(TokenType.UNPIVOT):
3994            unpivot = True
3995
3996            # https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
3997            if self._match_text_seq("INCLUDE", "NULLS"):
3998                include_nulls = True
3999            elif self._match_text_seq("EXCLUDE", "NULLS"):
4000                include_nulls = False
4001        else:
4002            return None
4003
4004        expressions = []
4005
4006        if not self._match(TokenType.L_PAREN):
4007            self._retreat(index)
4008            return None
4009
4010        if unpivot:
4011            expressions = self._parse_csv(self._parse_column)
4012        else:
4013            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
4014
4015        if not expressions:
4016            self.raise_error("Failed to parse PIVOT's aggregation list")
4017
4018        if not self._match(TokenType.FOR):
4019            self.raise_error("Expecting FOR")
4020
4021        field = self._parse_pivot_in()
4022        default_on_null = self._match_text_seq("DEFAULT", "ON", "NULL") and self._parse_wrapped(
4023            self._parse_bitwise
4024        )
4025
4026        self._match_r_paren()
4027
4028        pivot = self.expression(
4029            exp.Pivot,
4030            expressions=expressions,
4031            field=field,
4032            unpivot=unpivot,
4033            include_nulls=include_nulls,
4034            default_on_null=default_on_null,
4035        )
4036
4037        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
4038            pivot.set("alias", self._parse_table_alias())
4039
4040        if not unpivot:
4041            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
4042
4043            columns: t.List[exp.Expression] = []
4044            for fld in pivot.args["field"].expressions:
4045                field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
4046                for name in names:
4047                    if self.PREFIXED_PIVOT_COLUMNS:
4048                        name = f"{name}_{field_name}" if name else field_name
4049                    else:
4050                        name = f"{field_name}_{name}" if name else field_name
4051
4052                    columns.append(exp.to_identifier(name))
4053
4054            pivot.set("columns", columns)
4055
4056        return pivot
4057
4058    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
4059        return [agg.alias for agg in aggregations]
4060
4061    def _parse_prewhere(self, skip_where_token: bool = False) -> t.Optional[exp.PreWhere]:
4062        if not skip_where_token and not self._match(TokenType.PREWHERE):
4063            return None
4064
4065        return self.expression(
4066            exp.PreWhere, comments=self._prev_comments, this=self._parse_assignment()
4067        )
4068
4069    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
4070        if not skip_where_token and not self._match(TokenType.WHERE):
4071            return None
4072
4073        return self.expression(
4074            exp.Where, comments=self._prev_comments, this=self._parse_assignment()
4075        )
4076
4077    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
4078        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
4079            return None
4080
4081        elements: t.Dict[str, t.Any] = defaultdict(list)
4082
4083        if self._match(TokenType.ALL):
4084            elements["all"] = True
4085        elif self._match(TokenType.DISTINCT):
4086            elements["all"] = False
4087
4088        while True:
4089            index = self._index
4090
4091            elements["expressions"].extend(
4092                self._parse_csv(
4093                    lambda: None
4094                    if self._match_set((TokenType.CUBE, TokenType.ROLLUP), advance=False)
4095                    else self._parse_assignment()
4096                )
4097            )
4098
4099            before_with_index = self._index
4100            with_prefix = self._match(TokenType.WITH)
4101
4102            if self._match(TokenType.ROLLUP):
4103                elements["rollup"].append(
4104                    self._parse_cube_or_rollup(exp.Rollup, with_prefix=with_prefix)
4105                )
4106            elif self._match(TokenType.CUBE):
4107                elements["cube"].append(
4108                    self._parse_cube_or_rollup(exp.Cube, with_prefix=with_prefix)
4109                )
4110            elif self._match(TokenType.GROUPING_SETS):
4111                elements["grouping_sets"].append(
4112                    self.expression(
4113                        exp.GroupingSets,
4114                        expressions=self._parse_wrapped_csv(self._parse_grouping_set),
4115                    )
4116                )
4117            elif self._match_text_seq("TOTALS"):
4118                elements["totals"] = True  # type: ignore
4119
4120            if before_with_index <= self._index <= before_with_index + 1:
4121                self._retreat(before_with_index)
4122                break
4123
4124            if index == self._index:
4125                break
4126
4127        return self.expression(exp.Group, **elements)  # type: ignore
4128
4129    def _parse_cube_or_rollup(self, kind: t.Type[E], with_prefix: bool = False) -> E:
4130        return self.expression(
4131            kind, expressions=[] if with_prefix else self._parse_wrapped_csv(self._parse_column)
4132        )
4133
4134    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
4135        if self._match(TokenType.L_PAREN):
4136            grouping_set = self._parse_csv(self._parse_column)
4137            self._match_r_paren()
4138            return self.expression(exp.Tuple, expressions=grouping_set)
4139
4140        return self._parse_column()
4141
4142    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
4143        if not skip_having_token and not self._match(TokenType.HAVING):
4144            return None
4145        return self.expression(exp.Having, this=self._parse_assignment())
4146
4147    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
4148        if not self._match(TokenType.QUALIFY):
4149            return None
4150        return self.expression(exp.Qualify, this=self._parse_assignment())
4151
4152    def _parse_connect(self, skip_start_token: bool = False) -> t.Optional[exp.Connect]:
4153        if skip_start_token:
4154            start = None
4155        elif self._match(TokenType.START_WITH):
4156            start = self._parse_assignment()
4157        else:
4158            return None
4159
4160        self._match(TokenType.CONNECT_BY)
4161        nocycle = self._match_text_seq("NOCYCLE")
4162        self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
4163            exp.Prior, this=self._parse_bitwise()
4164        )
4165        connect = self._parse_assignment()
4166        self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
4167
4168        if not start and self._match(TokenType.START_WITH):
4169            start = self._parse_assignment()
4170
4171        return self.expression(exp.Connect, start=start, connect=connect, nocycle=nocycle)
4172
4173    def _parse_name_as_expression(self) -> t.Optional[exp.Expression]:
4174        this = self._parse_id_var(any_token=True)
4175        if self._match(TokenType.ALIAS):
4176            this = self.expression(exp.Alias, alias=this, this=self._parse_assignment())
4177        return this
4178
4179    def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
4180        if self._match_text_seq("INTERPOLATE"):
4181            return self._parse_wrapped_csv(self._parse_name_as_expression)
4182        return None
4183
4184    def _parse_order(
4185        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
4186    ) -> t.Optional[exp.Expression]:
4187        siblings = None
4188        if not skip_order_token and not self._match(TokenType.ORDER_BY):
4189            if not self._match(TokenType.ORDER_SIBLINGS_BY):
4190                return this
4191
4192            siblings = True
4193
4194        return self.expression(
4195            exp.Order,
4196            this=this,
4197            expressions=self._parse_csv(self._parse_ordered),
4198            siblings=siblings,
4199        )
4200
4201    def _parse_sort(self, exp_class: t.Type[E], token: TokenType) -> t.Optional[E]:
4202        if not self._match(token):
4203            return None
4204        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
4205
4206    def _parse_ordered(
4207        self, parse_method: t.Optional[t.Callable] = None
4208    ) -> t.Optional[exp.Ordered]:
4209        this = parse_method() if parse_method else self._parse_assignment()
4210        if not this:
4211            return None
4212
4213        if this.name.upper() == "ALL" and self.dialect.SUPPORTS_ORDER_BY_ALL:
4214            this = exp.var("ALL")
4215
4216        asc = self._match(TokenType.ASC)
4217        desc = self._match(TokenType.DESC) or (asc and False)
4218
4219        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
4220        is_nulls_last = self._match_text_seq("NULLS", "LAST")
4221
4222        nulls_first = is_nulls_first or False
4223        explicitly_null_ordered = is_nulls_first or is_nulls_last
4224
4225        if (
4226            not explicitly_null_ordered
4227            and (
4228                (not desc and self.dialect.NULL_ORDERING == "nulls_are_small")
4229                or (desc and self.dialect.NULL_ORDERING != "nulls_are_small")
4230            )
4231            and self.dialect.NULL_ORDERING != "nulls_are_last"
4232        ):
4233            nulls_first = True
4234
4235        if self._match_text_seq("WITH", "FILL"):
4236            with_fill = self.expression(
4237                exp.WithFill,
4238                **{  # type: ignore
4239                    "from": self._match(TokenType.FROM) and self._parse_bitwise(),
4240                    "to": self._match_text_seq("TO") and self._parse_bitwise(),
4241                    "step": self._match_text_seq("STEP") and self._parse_bitwise(),
4242                    "interpolate": self._parse_interpolate(),
4243                },
4244            )
4245        else:
4246            with_fill = None
4247
4248        return self.expression(
4249            exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
4250        )
4251
4252    def _parse_limit(
4253        self,
4254        this: t.Optional[exp.Expression] = None,
4255        top: bool = False,
4256        skip_limit_token: bool = False,
4257    ) -> t.Optional[exp.Expression]:
4258        if skip_limit_token or self._match(TokenType.TOP if top else TokenType.LIMIT):
4259            comments = self._prev_comments
4260            if top:
4261                limit_paren = self._match(TokenType.L_PAREN)
4262                expression = self._parse_term() if limit_paren else self._parse_number()
4263
4264                if limit_paren:
4265                    self._match_r_paren()
4266            else:
4267                expression = self._parse_term()
4268
4269            if self._match(TokenType.COMMA):
4270                offset = expression
4271                expression = self._parse_term()
4272            else:
4273                offset = None
4274
4275            limit_exp = self.expression(
4276                exp.Limit,
4277                this=this,
4278                expression=expression,
4279                offset=offset,
4280                comments=comments,
4281                expressions=self._parse_limit_by(),
4282            )
4283
4284            return limit_exp
4285
4286        if self._match(TokenType.FETCH):
4287            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
4288            direction = self._prev.text.upper() if direction else "FIRST"
4289
4290            count = self._parse_field(tokens=self.FETCH_TOKENS)
4291            percent = self._match(TokenType.PERCENT)
4292
4293            self._match_set((TokenType.ROW, TokenType.ROWS))
4294
4295            only = self._match_text_seq("ONLY")
4296            with_ties = self._match_text_seq("WITH", "TIES")
4297
4298            if only and with_ties:
4299                self.raise_error("Cannot specify both ONLY and WITH TIES in FETCH clause")
4300
4301            return self.expression(
4302                exp.Fetch,
4303                direction=direction,
4304                count=count,
4305                percent=percent,
4306                with_ties=with_ties,
4307            )
4308
4309        return this
4310
4311    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4312        if not self._match(TokenType.OFFSET):
4313            return this
4314
4315        count = self._parse_term()
4316        self._match_set((TokenType.ROW, TokenType.ROWS))
4317
4318        return self.expression(
4319            exp.Offset, this=this, expression=count, expressions=self._parse_limit_by()
4320        )
4321
4322    def _parse_limit_by(self) -> t.Optional[t.List[exp.Expression]]:
4323        return self._match_text_seq("BY") and self._parse_csv(self._parse_bitwise)
4324
4325    def _parse_locks(self) -> t.List[exp.Lock]:
4326        locks = []
4327        while True:
4328            if self._match_text_seq("FOR", "UPDATE"):
4329                update = True
4330            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
4331                "LOCK", "IN", "SHARE", "MODE"
4332            ):
4333                update = False
4334            else:
4335                break
4336
4337            expressions = None
4338            if self._match_text_seq("OF"):
4339                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
4340
4341            wait: t.Optional[bool | exp.Expression] = None
4342            if self._match_text_seq("NOWAIT"):
4343                wait = True
4344            elif self._match_text_seq("WAIT"):
4345                wait = self._parse_primary()
4346            elif self._match_text_seq("SKIP", "LOCKED"):
4347                wait = False
4348
4349            locks.append(
4350                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
4351            )
4352
4353        return locks
4354
4355    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4356        while this and self._match_set(self.SET_OPERATIONS):
4357            token_type = self._prev.token_type
4358
4359            if token_type == TokenType.UNION:
4360                operation: t.Type[exp.SetOperation] = exp.Union
4361            elif token_type == TokenType.EXCEPT:
4362                operation = exp.Except
4363            else:
4364                operation = exp.Intersect
4365
4366            comments = self._prev.comments
4367
4368            if self._match(TokenType.DISTINCT):
4369                distinct: t.Optional[bool] = True
4370            elif self._match(TokenType.ALL):
4371                distinct = False
4372            else:
4373                distinct = self.dialect.SET_OP_DISTINCT_BY_DEFAULT[operation]
4374                if distinct is None:
4375                    self.raise_error(f"Expected DISTINCT or ALL for {operation.__name__}")
4376
4377            by_name = self._match_text_seq("BY", "NAME")
4378            expression = self._parse_select(nested=True, parse_set_operation=False)
4379
4380            this = self.expression(
4381                operation,
4382                comments=comments,
4383                this=this,
4384                distinct=distinct,
4385                by_name=by_name,
4386                expression=expression,
4387            )
4388
4389        if isinstance(this, exp.SetOperation) and self.MODIFIERS_ATTACHED_TO_SET_OP:
4390            expression = this.expression
4391
4392            if expression:
4393                for arg in self.SET_OP_MODIFIERS:
4394                    expr = expression.args.get(arg)
4395                    if expr:
4396                        this.set(arg, expr.pop())
4397
4398        return this
4399
4400    def _parse_expression(self) -> t.Optional[exp.Expression]:
4401        return self._parse_alias(self._parse_assignment())
4402
4403    def _parse_assignment(self) -> t.Optional[exp.Expression]:
4404        this = self._parse_disjunction()
4405        if not this and self._next and self._next.token_type in self.ASSIGNMENT:
4406            # This allows us to parse <non-identifier token> := <expr>
4407            this = exp.column(
4408                t.cast(str, self._advance_any(ignore_reserved=True) and self._prev.text)
4409            )
4410
4411        while self._match_set(self.ASSIGNMENT):
4412            if isinstance(this, exp.Column) and len(this.parts) == 1:
4413                this = this.this
4414
4415            this = self.expression(
4416                self.ASSIGNMENT[self._prev.token_type],
4417                this=this,
4418                comments=self._prev_comments,
4419                expression=self._parse_assignment(),
4420            )
4421
4422        return this
4423
4424    def _parse_disjunction(self) -> t.Optional[exp.Expression]:
4425        return self._parse_tokens(self._parse_conjunction, self.DISJUNCTION)
4426
4427    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
4428        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
4429
4430    def _parse_equality(self) -> t.Optional[exp.Expression]:
4431        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
4432
4433    def _parse_comparison(self) -> t.Optional[exp.Expression]:
4434        return self._parse_tokens(self._parse_range, self.COMPARISON)
4435
4436    def _parse_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4437        this = this or self._parse_bitwise()
4438        negate = self._match(TokenType.NOT)
4439
4440        if self._match_set(self.RANGE_PARSERS):
4441            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
4442            if not expression:
4443                return this
4444
4445            this = expression
4446        elif self._match(TokenType.ISNULL):
4447            this = self.expression(exp.Is, this=this, expression=exp.Null())
4448
4449        # Postgres supports ISNULL and NOTNULL for conditions.
4450        # https://blog.andreiavram.ro/postgresql-null-composite-type/
4451        if self._match(TokenType.NOTNULL):
4452            this = self.expression(exp.Is, this=this, expression=exp.Null())
4453            this = self.expression(exp.Not, this=this)
4454
4455        if negate:
4456            this = self._negate_range(this)
4457
4458        if self._match(TokenType.IS):
4459            this = self._parse_is(this)
4460
4461        return this
4462
4463    def _negate_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4464        if not this:
4465            return this
4466
4467        return self.expression(exp.Not, this=this)
4468
4469    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4470        index = self._index - 1
4471        negate = self._match(TokenType.NOT)
4472
4473        if self._match_text_seq("DISTINCT", "FROM"):
4474            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
4475            return self.expression(klass, this=this, expression=self._parse_bitwise())
4476
4477        if self._match(TokenType.JSON):
4478            kind = self._match_texts(self.IS_JSON_PREDICATE_KIND) and self._prev.text.upper()
4479
4480            if self._match_text_seq("WITH"):
4481                _with = True
4482            elif self._match_text_seq("WITHOUT"):
4483                _with = False
4484            else:
4485                _with = None
4486
4487            unique = self._match(TokenType.UNIQUE)
4488            self._match_text_seq("KEYS")
4489            expression: t.Optional[exp.Expression] = self.expression(
4490                exp.JSON, **{"this": kind, "with": _with, "unique": unique}
4491            )
4492        else:
4493            expression = self._parse_primary() or self._parse_null()
4494            if not expression:
4495                self._retreat(index)
4496                return None
4497
4498        this = self.expression(exp.Is, this=this, expression=expression)
4499        return self.expression(exp.Not, this=this) if negate else this
4500
4501    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
4502        unnest = self._parse_unnest(with_alias=False)
4503        if unnest:
4504            this = self.expression(exp.In, this=this, unnest=unnest)
4505        elif self._match_set((TokenType.L_PAREN, TokenType.L_BRACKET)):
4506            matched_l_paren = self._prev.token_type == TokenType.L_PAREN
4507            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
4508
4509            if len(expressions) == 1 and isinstance(expressions[0], exp.Query):
4510                this = self.expression(exp.In, this=this, query=expressions[0].subquery(copy=False))
4511            else:
4512                this = self.expression(exp.In, this=this, expressions=expressions)
4513
4514            if matched_l_paren:
4515                self._match_r_paren(this)
4516            elif not self._match(TokenType.R_BRACKET, expression=this):
4517                self.raise_error("Expecting ]")
4518        else:
4519            this = self.expression(exp.In, this=this, field=self._parse_column())
4520
4521        return this
4522
4523    def _parse_between(self, this: t.Optional[exp.Expression]) -> exp.Between:
4524        low = self._parse_bitwise()
4525        self._match(TokenType.AND)
4526        high = self._parse_bitwise()
4527        return self.expression(exp.Between, this=this, low=low, high=high)
4528
4529    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4530        if not self._match(TokenType.ESCAPE):
4531            return this
4532        return self.expression(exp.Escape, this=this, expression=self._parse_string())
4533
4534    def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Add | exp.Interval]:
4535        index = self._index
4536
4537        if not self._match(TokenType.INTERVAL) and match_interval:
4538            return None
4539
4540        if self._match(TokenType.STRING, advance=False):
4541            this = self._parse_primary()
4542        else:
4543            this = self._parse_term()
4544
4545        if not this or (
4546            isinstance(this, exp.Column)
4547            and not this.table
4548            and not this.this.quoted
4549            and this.name.upper() == "IS"
4550        ):
4551            self._retreat(index)
4552            return None
4553
4554        unit = self._parse_function() or (
4555            not self._match(TokenType.ALIAS, advance=False)
4556            and self._parse_var(any_token=True, upper=True)
4557        )
4558
4559        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
4560        # each INTERVAL expression into this canonical form so it's easy to transpile
4561        if this and this.is_number:
4562            this = exp.Literal.string(this.to_py())
4563        elif this and this.is_string:
4564            parts = exp.INTERVAL_STRING_RE.findall(this.name)
4565            if len(parts) == 1:
4566                if unit:
4567                    # Unconsume the eagerly-parsed unit, since the real unit was part of the string
4568                    self._retreat(self._index - 1)
4569
4570                this = exp.Literal.string(parts[0][0])
4571                unit = self.expression(exp.Var, this=parts[0][1].upper())
4572
4573        if self.INTERVAL_SPANS and self._match_text_seq("TO"):
4574            unit = self.expression(
4575                exp.IntervalSpan, this=unit, expression=self._parse_var(any_token=True, upper=True)
4576            )
4577
4578        interval = self.expression(exp.Interval, this=this, unit=unit)
4579
4580        index = self._index
4581        self._match(TokenType.PLUS)
4582
4583        # Convert INTERVAL 'val_1' unit_1 [+] ... [+] 'val_n' unit_n into a sum of intervals
4584        if self._match_set((TokenType.STRING, TokenType.NUMBER), advance=False):
4585            return self.expression(
4586                exp.Add, this=interval, expression=self._parse_interval(match_interval=False)
4587            )
4588
4589        self._retreat(index)
4590        return interval
4591
4592    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
4593        this = self._parse_term()
4594
4595        while True:
4596            if self._match_set(self.BITWISE):
4597                this = self.expression(
4598                    self.BITWISE[self._prev.token_type],
4599                    this=this,
4600                    expression=self._parse_term(),
4601                )
4602            elif self.dialect.DPIPE_IS_STRING_CONCAT and self._match(TokenType.DPIPE):
4603                this = self.expression(
4604                    exp.DPipe,
4605                    this=this,
4606                    expression=self._parse_term(),
4607                    safe=not self.dialect.STRICT_STRING_CONCAT,
4608                )
4609            elif self._match(TokenType.DQMARK):
4610                this = self.expression(
4611                    exp.Coalesce, this=this, expressions=ensure_list(self._parse_term())
4612                )
4613            elif self._match_pair(TokenType.LT, TokenType.LT):
4614                this = self.expression(
4615                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
4616                )
4617            elif self._match_pair(TokenType.GT, TokenType.GT):
4618                this = self.expression(
4619                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
4620                )
4621            else:
4622                break
4623
4624        return this
4625
4626    def _parse_term(self) -> t.Optional[exp.Expression]:
4627        this = self._parse_factor()
4628
4629        while self._match_set(self.TERM):
4630            klass = self.TERM[self._prev.token_type]
4631            comments = self._prev_comments
4632            expression = self._parse_factor()
4633
4634            this = self.expression(klass, this=this, comments=comments, expression=expression)
4635
4636            if isinstance(this, exp.Collate):
4637                expr = this.expression
4638
4639                # Preserve collations such as pg_catalog."default" (Postgres) as columns, otherwise
4640                # fallback to Identifier / Var
4641                if isinstance(expr, exp.Column) and len(expr.parts) == 1:
4642                    ident = expr.this
4643                    if isinstance(ident, exp.Identifier):
4644                        this.set("expression", ident if ident.quoted else exp.var(ident.name))
4645
4646        return this
4647
4648    def _parse_factor(self) -> t.Optional[exp.Expression]:
4649        parse_method = self._parse_exponent if self.EXPONENT else self._parse_unary
4650        this = parse_method()
4651
4652        while self._match_set(self.FACTOR):
4653            klass = self.FACTOR[self._prev.token_type]
4654            comments = self._prev_comments
4655            expression = parse_method()
4656
4657            if not expression and klass is exp.IntDiv and self._prev.text.isalpha():
4658                self._retreat(self._index - 1)
4659                return this
4660
4661            this = self.expression(klass, this=this, comments=comments, expression=expression)
4662
4663            if isinstance(this, exp.Div):
4664                this.args["typed"] = self.dialect.TYPED_DIVISION
4665                this.args["safe"] = self.dialect.SAFE_DIVISION
4666
4667        return this
4668
4669    def _parse_exponent(self) -> t.Optional[exp.Expression]:
4670        return self._parse_tokens(self._parse_unary, self.EXPONENT)
4671
4672    def _parse_unary(self) -> t.Optional[exp.Expression]:
4673        if self._match_set(self.UNARY_PARSERS):
4674            return self.UNARY_PARSERS[self._prev.token_type](self)
4675        return self._parse_at_time_zone(self._parse_type())
4676
4677    def _parse_type(
4678        self, parse_interval: bool = True, fallback_to_identifier: bool = False
4679    ) -> t.Optional[exp.Expression]:
4680        interval = parse_interval and self._parse_interval()
4681        if interval:
4682            return interval
4683
4684        index = self._index
4685        data_type = self._parse_types(check_func=True, allow_identifiers=False)
4686
4687        # parse_types() returns a Cast if we parsed BQ's inline constructor <type>(<values>) e.g.
4688        # STRUCT<a INT, b STRING>(1, 'foo'), which is canonicalized to CAST(<values> AS <type>)
4689        if isinstance(data_type, exp.Cast):
4690            # This constructor can contain ops directly after it, for instance struct unnesting:
4691            # STRUCT<a INT, b STRING>(1, 'foo').* --> CAST(STRUCT(1, 'foo') AS STRUCT<a iNT, b STRING).*
4692            return self._parse_column_ops(data_type)
4693
4694        if data_type:
4695            index2 = self._index
4696            this = self._parse_primary()
4697
4698            if isinstance(this, exp.Literal):
4699                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
4700                if parser:
4701                    return parser(self, this, data_type)
4702
4703                return self.expression(exp.Cast, this=this, to=data_type)
4704
4705            # The expressions arg gets set by the parser when we have something like DECIMAL(38, 0)
4706            # in the input SQL. In that case, we'll produce these tokens: DECIMAL ( 38 , 0 )
4707            #
4708            # If the index difference here is greater than 1, that means the parser itself must have
4709            # consumed additional tokens such as the DECIMAL scale and precision in the above example.
4710            #
4711            # If it's not greater than 1, then it must be 1, because we've consumed at least the type
4712            # keyword, meaning that the expressions arg of the DataType must have gotten set by a
4713            # callable in the TYPE_CONVERTERS mapping. For example, Snowflake converts DECIMAL to
4714            # DECIMAL(38, 0)) in order to facilitate the data type's transpilation.
4715            #
4716            # In these cases, we don't really want to return the converted type, but instead retreat
4717            # and try to parse a Column or Identifier in the section below.
4718            if data_type.expressions and index2 - index > 1:
4719                self._retreat(index2)
4720                return self._parse_column_ops(data_type)
4721
4722            self._retreat(index)
4723
4724        if fallback_to_identifier:
4725            return self._parse_id_var()
4726
4727        this = self._parse_column()
4728        return this and self._parse_column_ops(this)
4729
4730    def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
4731        this = self._parse_type()
4732        if not this:
4733            return None
4734
4735        if isinstance(this, exp.Column) and not this.table:
4736            this = exp.var(this.name.upper())
4737
4738        return self.expression(
4739            exp.DataTypeParam, this=this, expression=self._parse_var(any_token=True)
4740        )
4741
4742    def _parse_types(
4743        self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
4744    ) -> t.Optional[exp.Expression]:
4745        index = self._index
4746
4747        this: t.Optional[exp.Expression] = None
4748        prefix = self._match_text_seq("SYSUDTLIB", ".")
4749
4750        if not self._match_set(self.TYPE_TOKENS):
4751            identifier = allow_identifiers and self._parse_id_var(
4752                any_token=False, tokens=(TokenType.VAR,)
4753            )
4754            if isinstance(identifier, exp.Identifier):
4755                tokens = self.dialect.tokenize(identifier.sql(dialect=self.dialect))
4756
4757                if len(tokens) != 1:
4758                    self.raise_error("Unexpected identifier", self._prev)
4759
4760                if tokens[0].token_type in self.TYPE_TOKENS:
4761                    self._prev = tokens[0]
4762                elif self.dialect.SUPPORTS_USER_DEFINED_TYPES:
4763                    type_name = identifier.name
4764
4765                    while self._match(TokenType.DOT):
4766                        type_name = f"{type_name}.{self._advance_any() and self._prev.text}"
4767
4768                    this = exp.DataType.build(type_name, udt=True)
4769                else:
4770                    self._retreat(self._index - 1)
4771                    return None
4772            else:
4773                return None
4774
4775        type_token = self._prev.token_type
4776
4777        if type_token == TokenType.PSEUDO_TYPE:
4778            return self.expression(exp.PseudoType, this=self._prev.text.upper())
4779
4780        if type_token == TokenType.OBJECT_IDENTIFIER:
4781            return self.expression(exp.ObjectIdentifier, this=self._prev.text.upper())
4782
4783        # https://materialize.com/docs/sql/types/map/
4784        if type_token == TokenType.MAP and self._match(TokenType.L_BRACKET):
4785            key_type = self._parse_types(
4786                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4787            )
4788            if not self._match(TokenType.FARROW):
4789                self._retreat(index)
4790                return None
4791
4792            value_type = self._parse_types(
4793                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4794            )
4795            if not self._match(TokenType.R_BRACKET):
4796                self._retreat(index)
4797                return None
4798
4799            return exp.DataType(
4800                this=exp.DataType.Type.MAP,
4801                expressions=[key_type, value_type],
4802                nested=True,
4803                prefix=prefix,
4804            )
4805
4806        nested = type_token in self.NESTED_TYPE_TOKENS
4807        is_struct = type_token in self.STRUCT_TYPE_TOKENS
4808        is_aggregate = type_token in self.AGGREGATE_TYPE_TOKENS
4809        expressions = None
4810        maybe_func = False
4811
4812        if self._match(TokenType.L_PAREN):
4813            if is_struct:
4814                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
4815            elif nested:
4816                expressions = self._parse_csv(
4817                    lambda: self._parse_types(
4818                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4819                    )
4820                )
4821                if type_token == TokenType.NULLABLE and len(expressions) == 1:
4822                    this = expressions[0]
4823                    this.set("nullable", True)
4824                    self._match_r_paren()
4825                    return this
4826            elif type_token in self.ENUM_TYPE_TOKENS:
4827                expressions = self._parse_csv(self._parse_equality)
4828            elif is_aggregate:
4829                func_or_ident = self._parse_function(anonymous=True) or self._parse_id_var(
4830                    any_token=False, tokens=(TokenType.VAR,)
4831                )
4832                if not func_or_ident or not self._match(TokenType.COMMA):
4833                    return None
4834                expressions = self._parse_csv(
4835                    lambda: self._parse_types(
4836                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4837                    )
4838                )
4839                expressions.insert(0, func_or_ident)
4840            else:
4841                expressions = self._parse_csv(self._parse_type_size)
4842
4843                # https://docs.snowflake.com/en/sql-reference/data-types-vector
4844                if type_token == TokenType.VECTOR and len(expressions) == 2:
4845                    expressions[0] = exp.DataType.build(expressions[0].name, dialect=self.dialect)
4846
4847            if not expressions or not self._match(TokenType.R_PAREN):
4848                self._retreat(index)
4849                return None
4850
4851            maybe_func = True
4852
4853        values: t.Optional[t.List[exp.Expression]] = None
4854
4855        if nested and self._match(TokenType.LT):
4856            if is_struct:
4857                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
4858            else:
4859                expressions = self._parse_csv(
4860                    lambda: self._parse_types(
4861                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4862                    )
4863                )
4864
4865            if not self._match(TokenType.GT):
4866                self.raise_error("Expecting >")
4867
4868            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
4869                values = self._parse_csv(self._parse_assignment)
4870                if not values and is_struct:
4871                    values = None
4872                    self._retreat(self._index - 1)
4873                else:
4874                    self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
4875
4876        if type_token in self.TIMESTAMPS:
4877            if self._match_text_seq("WITH", "TIME", "ZONE"):
4878                maybe_func = False
4879                tz_type = (
4880                    exp.DataType.Type.TIMETZ
4881                    if type_token in self.TIMES
4882                    else exp.DataType.Type.TIMESTAMPTZ
4883                )
4884                this = exp.DataType(this=tz_type, expressions=expressions)
4885            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
4886                maybe_func = False
4887                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
4888            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
4889                maybe_func = False
4890        elif type_token == TokenType.INTERVAL:
4891            unit = self._parse_var(upper=True)
4892            if unit:
4893                if self._match_text_seq("TO"):
4894                    unit = exp.IntervalSpan(this=unit, expression=self._parse_var(upper=True))
4895
4896                this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
4897            else:
4898                this = self.expression(exp.DataType, this=exp.DataType.Type.INTERVAL)
4899
4900        if maybe_func and check_func:
4901            index2 = self._index
4902            peek = self._parse_string()
4903
4904            if not peek:
4905                self._retreat(index)
4906                return None
4907
4908            self._retreat(index2)
4909
4910        if not this:
4911            if self._match_text_seq("UNSIGNED"):
4912                unsigned_type_token = self.SIGNED_TO_UNSIGNED_TYPE_TOKEN.get(type_token)
4913                if not unsigned_type_token:
4914                    self.raise_error(f"Cannot convert {type_token.value} to unsigned.")
4915
4916                type_token = unsigned_type_token or type_token
4917
4918            this = exp.DataType(
4919                this=exp.DataType.Type[type_token.value],
4920                expressions=expressions,
4921                nested=nested,
4922                prefix=prefix,
4923            )
4924
4925            # Empty arrays/structs are allowed
4926            if values is not None:
4927                cls = exp.Struct if is_struct else exp.Array
4928                this = exp.cast(cls(expressions=values), this, copy=False)
4929
4930        elif expressions:
4931            this.set("expressions", expressions)
4932
4933        # https://materialize.com/docs/sql/types/list/#type-name
4934        while self._match(TokenType.LIST):
4935            this = exp.DataType(this=exp.DataType.Type.LIST, expressions=[this], nested=True)
4936
4937        index = self._index
4938
4939        # Postgres supports the INT ARRAY[3] syntax as a synonym for INT[3]
4940        matched_array = self._match(TokenType.ARRAY)
4941
4942        while self._curr:
4943            datatype_token = self._prev.token_type
4944            matched_l_bracket = self._match(TokenType.L_BRACKET)
4945            if not matched_l_bracket and not matched_array:
4946                break
4947
4948            matched_array = False
4949            values = self._parse_csv(self._parse_assignment) or None
4950            if (
4951                values
4952                and not schema
4953                and (
4954                    not self.dialect.SUPPORTS_FIXED_SIZE_ARRAYS or datatype_token == TokenType.ARRAY
4955                )
4956            ):
4957                # Retreating here means that we should not parse the following values as part of the data type, e.g. in DuckDB
4958                # 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
4959                self._retreat(index)
4960                break
4961
4962            this = exp.DataType(
4963                this=exp.DataType.Type.ARRAY, expressions=[this], values=values, nested=True
4964            )
4965            self._match(TokenType.R_BRACKET)
4966
4967        if self.TYPE_CONVERTERS and isinstance(this.this, exp.DataType.Type):
4968            converter = self.TYPE_CONVERTERS.get(this.this)
4969            if converter:
4970                this = converter(t.cast(exp.DataType, this))
4971
4972        return this
4973
4974    def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
4975        index = self._index
4976
4977        if (
4978            self._curr
4979            and self._next
4980            and self._curr.token_type in self.TYPE_TOKENS
4981            and self._next.token_type in self.TYPE_TOKENS
4982        ):
4983            # Takes care of special cases like `STRUCT<list ARRAY<...>>` where the identifier is also a
4984            # type token. Without this, the list will be parsed as a type and we'll eventually crash
4985            this = self._parse_id_var()
4986        else:
4987            this = (
4988                self._parse_type(parse_interval=False, fallback_to_identifier=True)
4989                or self._parse_id_var()
4990            )
4991
4992        self._match(TokenType.COLON)
4993
4994        if (
4995            type_required
4996            and not isinstance(this, exp.DataType)
4997            and not self._match_set(self.TYPE_TOKENS, advance=False)
4998        ):
4999            self._retreat(index)
5000            return self._parse_types()
5001
5002        return self._parse_column_def(this)
5003
5004    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5005        if not self._match_text_seq("AT", "TIME", "ZONE"):
5006            return this
5007        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
5008
5009    def _parse_column(self) -> t.Optional[exp.Expression]:
5010        this = self._parse_column_reference()
5011        column = self._parse_column_ops(this) if this else self._parse_bracket(this)
5012
5013        if self.dialect.SUPPORTS_COLUMN_JOIN_MARKS and column:
5014            column.set("join_mark", self._match(TokenType.JOIN_MARKER))
5015
5016        return column
5017
5018    def _parse_column_reference(self) -> t.Optional[exp.Expression]:
5019        this = self._parse_field()
5020        if (
5021            not this
5022            and self._match(TokenType.VALUES, advance=False)
5023            and self.VALUES_FOLLOWED_BY_PAREN
5024            and (not self._next or self._next.token_type != TokenType.L_PAREN)
5025        ):
5026            this = self._parse_id_var()
5027
5028        if isinstance(this, exp.Identifier):
5029            # We bubble up comments from the Identifier to the Column
5030            this = self.expression(exp.Column, comments=this.pop_comments(), this=this)
5031
5032        return this
5033
5034    def _parse_colon_as_variant_extract(
5035        self, this: t.Optional[exp.Expression]
5036    ) -> t.Optional[exp.Expression]:
5037        casts = []
5038        json_path = []
5039        escape = None
5040
5041        while self._match(TokenType.COLON):
5042            start_index = self._index
5043
5044            # Snowflake allows reserved keywords as json keys but advance_any() excludes TokenType.SELECT from any_tokens=True
5045            path = self._parse_column_ops(
5046                self._parse_field(any_token=True, tokens=(TokenType.SELECT,))
5047            )
5048
5049            # The cast :: operator has a lower precedence than the extraction operator :, so
5050            # we rearrange the AST appropriately to avoid casting the JSON path
5051            while isinstance(path, exp.Cast):
5052                casts.append(path.to)
5053                path = path.this
5054
5055            if casts:
5056                dcolon_offset = next(
5057                    i
5058                    for i, t in enumerate(self._tokens[start_index:])
5059                    if t.token_type == TokenType.DCOLON
5060                )
5061                end_token = self._tokens[start_index + dcolon_offset - 1]
5062            else:
5063                end_token = self._prev
5064
5065            if path:
5066                # Escape single quotes from Snowflake's colon extraction (e.g. col:"a'b") as
5067                # it'll roundtrip to a string literal in GET_PATH
5068                if isinstance(path, exp.Identifier) and path.quoted:
5069                    escape = True
5070
5071                json_path.append(self._find_sql(self._tokens[start_index], end_token))
5072
5073        # The VARIANT extract in Snowflake/Databricks is parsed as a JSONExtract; Snowflake uses the json_path in GET_PATH() while
5074        # Databricks transforms it back to the colon/dot notation
5075        if json_path:
5076            json_path_expr = self.dialect.to_json_path(exp.Literal.string(".".join(json_path)))
5077
5078            if json_path_expr:
5079                json_path_expr.set("escape", escape)
5080
5081            this = self.expression(
5082                exp.JSONExtract,
5083                this=this,
5084                expression=json_path_expr,
5085                variant_extract=True,
5086            )
5087
5088            while casts:
5089                this = self.expression(exp.Cast, this=this, to=casts.pop())
5090
5091        return this
5092
5093    def _parse_dcolon(self) -> t.Optional[exp.Expression]:
5094        return self._parse_types()
5095
5096    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5097        this = self._parse_bracket(this)
5098
5099        while self._match_set(self.COLUMN_OPERATORS):
5100            op_token = self._prev.token_type
5101            op = self.COLUMN_OPERATORS.get(op_token)
5102
5103            if op_token == TokenType.DCOLON:
5104                field = self._parse_dcolon()
5105                if not field:
5106                    self.raise_error("Expected type")
5107            elif op and self._curr:
5108                field = self._parse_column_reference() or self._parse_bracket()
5109            else:
5110                field = self._parse_field(any_token=True, anonymous_func=True)
5111
5112            if isinstance(field, exp.Func) and this:
5113                # bigquery allows function calls like x.y.count(...)
5114                # SAFE.SUBSTR(...)
5115                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
5116                this = exp.replace_tree(
5117                    this,
5118                    lambda n: (
5119                        self.expression(exp.Dot, this=n.args.get("table"), expression=n.this)
5120                        if n.table
5121                        else n.this
5122                    )
5123                    if isinstance(n, exp.Column)
5124                    else n,
5125                )
5126
5127            if op:
5128                this = op(self, this, field)
5129            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
5130                this = self.expression(
5131                    exp.Column,
5132                    comments=this.comments,
5133                    this=field,
5134                    table=this.this,
5135                    db=this.args.get("table"),
5136                    catalog=this.args.get("db"),
5137                )
5138            else:
5139                this = self.expression(exp.Dot, this=this, expression=field)
5140
5141            this = self._parse_bracket(this)
5142
5143        return self._parse_colon_as_variant_extract(this) if self.COLON_IS_VARIANT_EXTRACT else this
5144
5145    def _parse_primary(self) -> t.Optional[exp.Expression]:
5146        if self._match_set(self.PRIMARY_PARSERS):
5147            token_type = self._prev.token_type
5148            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
5149
5150            if token_type == TokenType.STRING:
5151                expressions = [primary]
5152                while self._match(TokenType.STRING):
5153                    expressions.append(exp.Literal.string(self._prev.text))
5154
5155                if len(expressions) > 1:
5156                    return self.expression(exp.Concat, expressions=expressions)
5157
5158            return primary
5159
5160        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
5161            return exp.Literal.number(f"0.{self._prev.text}")
5162
5163        if self._match(TokenType.L_PAREN):
5164            comments = self._prev_comments
5165            query = self._parse_select()
5166
5167            if query:
5168                expressions = [query]
5169            else:
5170                expressions = self._parse_expressions()
5171
5172            this = self._parse_query_modifiers(seq_get(expressions, 0))
5173
5174            if not this and self._match(TokenType.R_PAREN, advance=False):
5175                this = self.expression(exp.Tuple)
5176            elif isinstance(this, exp.UNWRAPPED_QUERIES):
5177                this = self._parse_subquery(this=this, parse_alias=False)
5178            elif isinstance(this, exp.Subquery):
5179                this = self._parse_subquery(
5180                    this=self._parse_set_operations(this), parse_alias=False
5181                )
5182            elif len(expressions) > 1 or self._prev.token_type == TokenType.COMMA:
5183                this = self.expression(exp.Tuple, expressions=expressions)
5184            else:
5185                this = self.expression(exp.Paren, this=this)
5186
5187            if this:
5188                this.add_comments(comments)
5189
5190            self._match_r_paren(expression=this)
5191            return this
5192
5193        return None
5194
5195    def _parse_field(
5196        self,
5197        any_token: bool = False,
5198        tokens: t.Optional[t.Collection[TokenType]] = None,
5199        anonymous_func: bool = False,
5200    ) -> t.Optional[exp.Expression]:
5201        if anonymous_func:
5202            field = (
5203                self._parse_function(anonymous=anonymous_func, any_token=any_token)
5204                or self._parse_primary()
5205            )
5206        else:
5207            field = self._parse_primary() or self._parse_function(
5208                anonymous=anonymous_func, any_token=any_token
5209            )
5210        return field or self._parse_id_var(any_token=any_token, tokens=tokens)
5211
5212    def _parse_function(
5213        self,
5214        functions: t.Optional[t.Dict[str, t.Callable]] = None,
5215        anonymous: bool = False,
5216        optional_parens: bool = True,
5217        any_token: bool = False,
5218    ) -> t.Optional[exp.Expression]:
5219        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
5220        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
5221        fn_syntax = False
5222        if (
5223            self._match(TokenType.L_BRACE, advance=False)
5224            and self._next
5225            and self._next.text.upper() == "FN"
5226        ):
5227            self._advance(2)
5228            fn_syntax = True
5229
5230        func = self._parse_function_call(
5231            functions=functions,
5232            anonymous=anonymous,
5233            optional_parens=optional_parens,
5234            any_token=any_token,
5235        )
5236
5237        if fn_syntax:
5238            self._match(TokenType.R_BRACE)
5239
5240        return func
5241
5242    def _parse_function_call(
5243        self,
5244        functions: t.Optional[t.Dict[str, t.Callable]] = None,
5245        anonymous: bool = False,
5246        optional_parens: bool = True,
5247        any_token: bool = False,
5248    ) -> t.Optional[exp.Expression]:
5249        if not self._curr:
5250            return None
5251
5252        comments = self._curr.comments
5253        token_type = self._curr.token_type
5254        this = self._curr.text
5255        upper = this.upper()
5256
5257        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
5258        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
5259            self._advance()
5260            return self._parse_window(parser(self))
5261
5262        if not self._next or self._next.token_type != TokenType.L_PAREN:
5263            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
5264                self._advance()
5265                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
5266
5267            return None
5268
5269        if any_token:
5270            if token_type in self.RESERVED_TOKENS:
5271                return None
5272        elif token_type not in self.FUNC_TOKENS:
5273            return None
5274
5275        self._advance(2)
5276
5277        parser = self.FUNCTION_PARSERS.get(upper)
5278        if parser and not anonymous:
5279            this = parser(self)
5280        else:
5281            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
5282
5283            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
5284                this = self.expression(
5285                    subquery_predicate, comments=comments, this=self._parse_select()
5286                )
5287                self._match_r_paren()
5288                return this
5289
5290            if functions is None:
5291                functions = self.FUNCTIONS
5292
5293            function = functions.get(upper)
5294
5295            alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS
5296            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
5297
5298            if alias:
5299                args = self._kv_to_prop_eq(args)
5300
5301            if function and not anonymous:
5302                if "dialect" in function.__code__.co_varnames:
5303                    func = function(args, dialect=self.dialect)
5304                else:
5305                    func = function(args)
5306
5307                func = self.validate_expression(func, args)
5308                if not self.dialect.NORMALIZE_FUNCTIONS:
5309                    func.meta["name"] = this
5310
5311                this = func
5312            else:
5313                if token_type == TokenType.IDENTIFIER:
5314                    this = exp.Identifier(this=this, quoted=True)
5315                this = self.expression(exp.Anonymous, this=this, expressions=args)
5316
5317        if isinstance(this, exp.Expression):
5318            this.add_comments(comments)
5319
5320        self._match_r_paren(this)
5321        return self._parse_window(this)
5322
5323    def _to_prop_eq(self, expression: exp.Expression, index: int) -> exp.Expression:
5324        return expression
5325
5326    def _kv_to_prop_eq(self, expressions: t.List[exp.Expression]) -> t.List[exp.Expression]:
5327        transformed = []
5328
5329        for index, e in enumerate(expressions):
5330            if isinstance(e, self.KEY_VALUE_DEFINITIONS):
5331                if isinstance(e, exp.Alias):
5332                    e = self.expression(exp.PropertyEQ, this=e.args.get("alias"), expression=e.this)
5333
5334                if not isinstance(e, exp.PropertyEQ):
5335                    e = self.expression(
5336                        exp.PropertyEQ, this=exp.to_identifier(e.this.name), expression=e.expression
5337                    )
5338
5339                if isinstance(e.this, exp.Column):
5340                    e.this.replace(e.this.this)
5341            else:
5342                e = self._to_prop_eq(e, index)
5343
5344            transformed.append(e)
5345
5346        return transformed
5347
5348    def _parse_user_defined_function_expression(self) -> t.Optional[exp.Expression]:
5349        return self._parse_statement()
5350
5351    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
5352        return self._parse_column_def(self._parse_id_var())
5353
5354    def _parse_user_defined_function(
5355        self, kind: t.Optional[TokenType] = None
5356    ) -> t.Optional[exp.Expression]:
5357        this = self._parse_id_var()
5358
5359        while self._match(TokenType.DOT):
5360            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
5361
5362        if not self._match(TokenType.L_PAREN):
5363            return this
5364
5365        expressions = self._parse_csv(self._parse_function_parameter)
5366        self._match_r_paren()
5367        return self.expression(
5368            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
5369        )
5370
5371    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
5372        literal = self._parse_primary()
5373        if literal:
5374            return self.expression(exp.Introducer, this=token.text, expression=literal)
5375
5376        return self.expression(exp.Identifier, this=token.text)
5377
5378    def _parse_session_parameter(self) -> exp.SessionParameter:
5379        kind = None
5380        this = self._parse_id_var() or self._parse_primary()
5381
5382        if this and self._match(TokenType.DOT):
5383            kind = this.name
5384            this = self._parse_var() or self._parse_primary()
5385
5386        return self.expression(exp.SessionParameter, this=this, kind=kind)
5387
5388    def _parse_lambda_arg(self) -> t.Optional[exp.Expression]:
5389        return self._parse_id_var()
5390
5391    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
5392        index = self._index
5393
5394        if self._match(TokenType.L_PAREN):
5395            expressions = t.cast(
5396                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_lambda_arg)
5397            )
5398
5399            if not self._match(TokenType.R_PAREN):
5400                self._retreat(index)
5401        else:
5402            expressions = [self._parse_lambda_arg()]
5403
5404        if self._match_set(self.LAMBDAS):
5405            return self.LAMBDAS[self._prev.token_type](self, expressions)
5406
5407        self._retreat(index)
5408
5409        this: t.Optional[exp.Expression]
5410
5411        if self._match(TokenType.DISTINCT):
5412            this = self.expression(
5413                exp.Distinct, expressions=self._parse_csv(self._parse_assignment)
5414            )
5415        else:
5416            this = self._parse_select_or_expression(alias=alias)
5417
5418        return self._parse_limit(
5419            self._parse_order(self._parse_having_max(self._parse_respect_or_ignore_nulls(this)))
5420        )
5421
5422    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
5423        index = self._index
5424        if not self._match(TokenType.L_PAREN):
5425            return this
5426
5427        # Disambiguate between schema and subquery/CTE, e.g. in INSERT INTO table (<expr>),
5428        # expr can be of both types
5429        if self._match_set(self.SELECT_START_TOKENS):
5430            self._retreat(index)
5431            return this
5432        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
5433        self._match_r_paren()
5434        return self.expression(exp.Schema, this=this, expressions=args)
5435
5436    def _parse_field_def(self) -> t.Optional[exp.Expression]:
5437        return self._parse_column_def(self._parse_field(any_token=True))
5438
5439    def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5440        # column defs are not really columns, they're identifiers
5441        if isinstance(this, exp.Column):
5442            this = this.this
5443
5444        kind = self._parse_types(schema=True)
5445
5446        if self._match_text_seq("FOR", "ORDINALITY"):
5447            return self.expression(exp.ColumnDef, this=this, ordinality=True)
5448
5449        constraints: t.List[exp.Expression] = []
5450
5451        if (not kind and self._match(TokenType.ALIAS)) or self._match_texts(
5452            ("ALIAS", "MATERIALIZED")
5453        ):
5454            persisted = self._prev.text.upper() == "MATERIALIZED"
5455            constraint_kind = exp.ComputedColumnConstraint(
5456                this=self._parse_assignment(),
5457                persisted=persisted or self._match_text_seq("PERSISTED"),
5458                not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
5459            )
5460            constraints.append(self.expression(exp.ColumnConstraint, kind=constraint_kind))
5461        elif kind and self._match_pair(TokenType.ALIAS, TokenType.L_PAREN, advance=False):
5462            self._match(TokenType.ALIAS)
5463            constraints.append(
5464                self.expression(
5465                    exp.ColumnConstraint,
5466                    kind=exp.TransformColumnConstraint(this=self._parse_field()),
5467                )
5468            )
5469
5470        while True:
5471            constraint = self._parse_column_constraint()
5472            if not constraint:
5473                break
5474            constraints.append(constraint)
5475
5476        if not kind and not constraints:
5477            return this
5478
5479        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
5480
5481    def _parse_auto_increment(
5482        self,
5483    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
5484        start = None
5485        increment = None
5486
5487        if self._match(TokenType.L_PAREN, advance=False):
5488            args = self._parse_wrapped_csv(self._parse_bitwise)
5489            start = seq_get(args, 0)
5490            increment = seq_get(args, 1)
5491        elif self._match_text_seq("START"):
5492            start = self._parse_bitwise()
5493            self._match_text_seq("INCREMENT")
5494            increment = self._parse_bitwise()
5495
5496        if start and increment:
5497            return exp.GeneratedAsIdentityColumnConstraint(start=start, increment=increment)
5498
5499        return exp.AutoIncrementColumnConstraint()
5500
5501    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
5502        if not self._match_text_seq("REFRESH"):
5503            self._retreat(self._index - 1)
5504            return None
5505        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
5506
5507    def _parse_compress(self) -> exp.CompressColumnConstraint:
5508        if self._match(TokenType.L_PAREN, advance=False):
5509            return self.expression(
5510                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
5511            )
5512
5513        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
5514
5515    def _parse_generated_as_identity(
5516        self,
5517    ) -> (
5518        exp.GeneratedAsIdentityColumnConstraint
5519        | exp.ComputedColumnConstraint
5520        | exp.GeneratedAsRowColumnConstraint
5521    ):
5522        if self._match_text_seq("BY", "DEFAULT"):
5523            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
5524            this = self.expression(
5525                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
5526            )
5527        else:
5528            self._match_text_seq("ALWAYS")
5529            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
5530
5531        self._match(TokenType.ALIAS)
5532
5533        if self._match_text_seq("ROW"):
5534            start = self._match_text_seq("START")
5535            if not start:
5536                self._match(TokenType.END)
5537            hidden = self._match_text_seq("HIDDEN")
5538            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
5539
5540        identity = self._match_text_seq("IDENTITY")
5541
5542        if self._match(TokenType.L_PAREN):
5543            if self._match(TokenType.START_WITH):
5544                this.set("start", self._parse_bitwise())
5545            if self._match_text_seq("INCREMENT", "BY"):
5546                this.set("increment", self._parse_bitwise())
5547            if self._match_text_seq("MINVALUE"):
5548                this.set("minvalue", self._parse_bitwise())
5549            if self._match_text_seq("MAXVALUE"):
5550                this.set("maxvalue", self._parse_bitwise())
5551
5552            if self._match_text_seq("CYCLE"):
5553                this.set("cycle", True)
5554            elif self._match_text_seq("NO", "CYCLE"):
5555                this.set("cycle", False)
5556
5557            if not identity:
5558                this.set("expression", self._parse_range())
5559            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
5560                args = self._parse_csv(self._parse_bitwise)
5561                this.set("start", seq_get(args, 0))
5562                this.set("increment", seq_get(args, 1))
5563
5564            self._match_r_paren()
5565
5566        return this
5567
5568    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
5569        self._match_text_seq("LENGTH")
5570        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
5571
5572    def _parse_not_constraint(self) -> t.Optional[exp.Expression]:
5573        if self._match_text_seq("NULL"):
5574            return self.expression(exp.NotNullColumnConstraint)
5575        if self._match_text_seq("CASESPECIFIC"):
5576            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
5577        if self._match_text_seq("FOR", "REPLICATION"):
5578            return self.expression(exp.NotForReplicationColumnConstraint)
5579
5580        # Unconsume the `NOT` token
5581        self._retreat(self._index - 1)
5582        return None
5583
5584    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
5585        this = self._match(TokenType.CONSTRAINT) and self._parse_id_var()
5586
5587        procedure_option_follows = (
5588            self._match(TokenType.WITH, advance=False)
5589            and self._next
5590            and self._next.text.upper() in self.PROCEDURE_OPTIONS
5591        )
5592
5593        if not procedure_option_follows and self._match_texts(self.CONSTRAINT_PARSERS):
5594            return self.expression(
5595                exp.ColumnConstraint,
5596                this=this,
5597                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
5598            )
5599
5600        return this
5601
5602    def _parse_constraint(self) -> t.Optional[exp.Expression]:
5603        if not self._match(TokenType.CONSTRAINT):
5604            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
5605
5606        return self.expression(
5607            exp.Constraint,
5608            this=self._parse_id_var(),
5609            expressions=self._parse_unnamed_constraints(),
5610        )
5611
5612    def _parse_unnamed_constraints(self) -> t.List[exp.Expression]:
5613        constraints = []
5614        while True:
5615            constraint = self._parse_unnamed_constraint() or self._parse_function()
5616            if not constraint:
5617                break
5618            constraints.append(constraint)
5619
5620        return constraints
5621
5622    def _parse_unnamed_constraint(
5623        self, constraints: t.Optional[t.Collection[str]] = None
5624    ) -> t.Optional[exp.Expression]:
5625        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
5626            constraints or self.CONSTRAINT_PARSERS
5627        ):
5628            return None
5629
5630        constraint = self._prev.text.upper()
5631        if constraint not in self.CONSTRAINT_PARSERS:
5632            self.raise_error(f"No parser found for schema constraint {constraint}.")
5633
5634        return self.CONSTRAINT_PARSERS[constraint](self)
5635
5636    def _parse_unique_key(self) -> t.Optional[exp.Expression]:
5637        return self._parse_id_var(any_token=False)
5638
5639    def _parse_unique(self) -> exp.UniqueColumnConstraint:
5640        self._match_text_seq("KEY")
5641        return self.expression(
5642            exp.UniqueColumnConstraint,
5643            nulls=self._match_text_seq("NULLS", "NOT", "DISTINCT"),
5644            this=self._parse_schema(self._parse_unique_key()),
5645            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
5646            on_conflict=self._parse_on_conflict(),
5647        )
5648
5649    def _parse_key_constraint_options(self) -> t.List[str]:
5650        options = []
5651        while True:
5652            if not self._curr:
5653                break
5654
5655            if self._match(TokenType.ON):
5656                action = None
5657                on = self._advance_any() and self._prev.text
5658
5659                if self._match_text_seq("NO", "ACTION"):
5660                    action = "NO ACTION"
5661                elif self._match_text_seq("CASCADE"):
5662                    action = "CASCADE"
5663                elif self._match_text_seq("RESTRICT"):
5664                    action = "RESTRICT"
5665                elif self._match_pair(TokenType.SET, TokenType.NULL):
5666                    action = "SET NULL"
5667                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
5668                    action = "SET DEFAULT"
5669                else:
5670                    self.raise_error("Invalid key constraint")
5671
5672                options.append(f"ON {on} {action}")
5673            else:
5674                var = self._parse_var_from_options(
5675                    self.KEY_CONSTRAINT_OPTIONS, raise_unmatched=False
5676                )
5677                if not var:
5678                    break
5679                options.append(var.name)
5680
5681        return options
5682
5683    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
5684        if match and not self._match(TokenType.REFERENCES):
5685            return None
5686
5687        expressions = None
5688        this = self._parse_table(schema=True)
5689        options = self._parse_key_constraint_options()
5690        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
5691
5692    def _parse_foreign_key(self) -> exp.ForeignKey:
5693        expressions = self._parse_wrapped_id_vars()
5694        reference = self._parse_references()
5695        options = {}
5696
5697        while self._match(TokenType.ON):
5698            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
5699                self.raise_error("Expected DELETE or UPDATE")
5700
5701            kind = self._prev.text.lower()
5702
5703            if self._match_text_seq("NO", "ACTION"):
5704                action = "NO ACTION"
5705            elif self._match(TokenType.SET):
5706                self._match_set((TokenType.NULL, TokenType.DEFAULT))
5707                action = "SET " + self._prev.text.upper()
5708            else:
5709                self._advance()
5710                action = self._prev.text.upper()
5711
5712            options[kind] = action
5713
5714        return self.expression(
5715            exp.ForeignKey,
5716            expressions=expressions,
5717            reference=reference,
5718            **options,  # type: ignore
5719        )
5720
5721    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
5722        return self._parse_field()
5723
5724    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
5725        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
5726            self._retreat(self._index - 1)
5727            return None
5728
5729        id_vars = self._parse_wrapped_id_vars()
5730        return self.expression(
5731            exp.PeriodForSystemTimeConstraint,
5732            this=seq_get(id_vars, 0),
5733            expression=seq_get(id_vars, 1),
5734        )
5735
5736    def _parse_primary_key(
5737        self, wrapped_optional: bool = False, in_props: bool = False
5738    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
5739        desc = (
5740            self._match_set((TokenType.ASC, TokenType.DESC))
5741            and self._prev.token_type == TokenType.DESC
5742        )
5743
5744        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
5745            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
5746
5747        expressions = self._parse_wrapped_csv(
5748            self._parse_primary_key_part, optional=wrapped_optional
5749        )
5750        options = self._parse_key_constraint_options()
5751        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
5752
5753    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
5754        return self._parse_slice(self._parse_alias(self._parse_assignment(), explicit=True))
5755
5756    def _parse_odbc_datetime_literal(self) -> exp.Expression:
5757        """
5758        Parses a datetime column in ODBC format. We parse the column into the corresponding
5759        types, for example `{d'yyyy-mm-dd'}` will be parsed as a `Date` column, exactly the
5760        same as we did for `DATE('yyyy-mm-dd')`.
5761
5762        Reference:
5763        https://learn.microsoft.com/en-us/sql/odbc/reference/develop-app/date-time-and-timestamp-literals
5764        """
5765        self._match(TokenType.VAR)
5766        exp_class = self.ODBC_DATETIME_LITERALS[self._prev.text.lower()]
5767        expression = self.expression(exp_class=exp_class, this=self._parse_string())
5768        if not self._match(TokenType.R_BRACE):
5769            self.raise_error("Expected }")
5770        return expression
5771
5772    def _parse_bracket(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
5773        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
5774            return this
5775
5776        bracket_kind = self._prev.token_type
5777        if (
5778            bracket_kind == TokenType.L_BRACE
5779            and self._curr
5780            and self._curr.token_type == TokenType.VAR
5781            and self._curr.text.lower() in self.ODBC_DATETIME_LITERALS
5782        ):
5783            return self._parse_odbc_datetime_literal()
5784
5785        expressions = self._parse_csv(
5786            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
5787        )
5788
5789        if bracket_kind == TokenType.L_BRACKET and not self._match(TokenType.R_BRACKET):
5790            self.raise_error("Expected ]")
5791        elif bracket_kind == TokenType.L_BRACE and not self._match(TokenType.R_BRACE):
5792            self.raise_error("Expected }")
5793
5794        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
5795        if bracket_kind == TokenType.L_BRACE:
5796            this = self.expression(exp.Struct, expressions=self._kv_to_prop_eq(expressions))
5797        elif not this:
5798            this = build_array_constructor(
5799                exp.Array, args=expressions, bracket_kind=bracket_kind, dialect=self.dialect
5800            )
5801        else:
5802            constructor_type = self.ARRAY_CONSTRUCTORS.get(this.name.upper())
5803            if constructor_type:
5804                return build_array_constructor(
5805                    constructor_type,
5806                    args=expressions,
5807                    bracket_kind=bracket_kind,
5808                    dialect=self.dialect,
5809                )
5810
5811            expressions = apply_index_offset(this, expressions, -self.dialect.INDEX_OFFSET)
5812            this = self.expression(exp.Bracket, this=this, expressions=expressions)
5813
5814        self._add_comments(this)
5815        return self._parse_bracket(this)
5816
5817    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5818        if self._match(TokenType.COLON):
5819            return self.expression(exp.Slice, this=this, expression=self._parse_assignment())
5820        return this
5821
5822    def _parse_case(self) -> t.Optional[exp.Expression]:
5823        ifs = []
5824        default = None
5825
5826        comments = self._prev_comments
5827        expression = self._parse_assignment()
5828
5829        while self._match(TokenType.WHEN):
5830            this = self._parse_assignment()
5831            self._match(TokenType.THEN)
5832            then = self._parse_assignment()
5833            ifs.append(self.expression(exp.If, this=this, true=then))
5834
5835        if self._match(TokenType.ELSE):
5836            default = self._parse_assignment()
5837
5838        if not self._match(TokenType.END):
5839            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
5840                default = exp.column("interval")
5841            else:
5842                self.raise_error("Expected END after CASE", self._prev)
5843
5844        return self.expression(
5845            exp.Case, comments=comments, this=expression, ifs=ifs, default=default
5846        )
5847
5848    def _parse_if(self) -> t.Optional[exp.Expression]:
5849        if self._match(TokenType.L_PAREN):
5850            args = self._parse_csv(self._parse_assignment)
5851            this = self.validate_expression(exp.If.from_arg_list(args), args)
5852            self._match_r_paren()
5853        else:
5854            index = self._index - 1
5855
5856            if self.NO_PAREN_IF_COMMANDS and index == 0:
5857                return self._parse_as_command(self._prev)
5858
5859            condition = self._parse_assignment()
5860
5861            if not condition:
5862                self._retreat(index)
5863                return None
5864
5865            self._match(TokenType.THEN)
5866            true = self._parse_assignment()
5867            false = self._parse_assignment() if self._match(TokenType.ELSE) else None
5868            self._match(TokenType.END)
5869            this = self.expression(exp.If, this=condition, true=true, false=false)
5870
5871        return this
5872
5873    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
5874        if not self._match_text_seq("VALUE", "FOR"):
5875            self._retreat(self._index - 1)
5876            return None
5877
5878        return self.expression(
5879            exp.NextValueFor,
5880            this=self._parse_column(),
5881            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
5882        )
5883
5884    def _parse_extract(self) -> exp.Extract | exp.Anonymous:
5885        this = self._parse_function() or self._parse_var_or_string(upper=True)
5886
5887        if self._match(TokenType.FROM):
5888            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
5889
5890        if not self._match(TokenType.COMMA):
5891            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
5892
5893        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
5894
5895    def _parse_gap_fill(self) -> exp.GapFill:
5896        self._match(TokenType.TABLE)
5897        this = self._parse_table()
5898
5899        self._match(TokenType.COMMA)
5900        args = [this, *self._parse_csv(self._parse_lambda)]
5901
5902        gap_fill = exp.GapFill.from_arg_list(args)
5903        return self.validate_expression(gap_fill, args)
5904
5905    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
5906        this = self._parse_assignment()
5907
5908        if not self._match(TokenType.ALIAS):
5909            if self._match(TokenType.COMMA):
5910                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
5911
5912            self.raise_error("Expected AS after CAST")
5913
5914        fmt = None
5915        to = self._parse_types()
5916
5917        if self._match(TokenType.FORMAT):
5918            fmt_string = self._parse_string()
5919            fmt = self._parse_at_time_zone(fmt_string)
5920
5921            if not to:
5922                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
5923            if to.this in exp.DataType.TEMPORAL_TYPES:
5924                this = self.expression(
5925                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
5926                    this=this,
5927                    format=exp.Literal.string(
5928                        format_time(
5929                            fmt_string.this if fmt_string else "",
5930                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
5931                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
5932                        )
5933                    ),
5934                    safe=safe,
5935                )
5936
5937                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
5938                    this.set("zone", fmt.args["zone"])
5939                return this
5940        elif not to:
5941            self.raise_error("Expected TYPE after CAST")
5942        elif isinstance(to, exp.Identifier):
5943            to = exp.DataType.build(to.name, udt=True)
5944        elif to.this == exp.DataType.Type.CHAR:
5945            if self._match(TokenType.CHARACTER_SET):
5946                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
5947
5948        return self.expression(
5949            exp.Cast if strict else exp.TryCast,
5950            this=this,
5951            to=to,
5952            format=fmt,
5953            safe=safe,
5954            action=self._parse_var_from_options(self.CAST_ACTIONS, raise_unmatched=False),
5955        )
5956
5957    def _parse_string_agg(self) -> exp.GroupConcat:
5958        if self._match(TokenType.DISTINCT):
5959            args: t.List[t.Optional[exp.Expression]] = [
5960                self.expression(exp.Distinct, expressions=[self._parse_assignment()])
5961            ]
5962            if self._match(TokenType.COMMA):
5963                args.extend(self._parse_csv(self._parse_assignment))
5964        else:
5965            args = self._parse_csv(self._parse_assignment)  # type: ignore
5966
5967        if self._match_text_seq("ON", "OVERFLOW"):
5968            # trino: LISTAGG(expression [, separator] [ON OVERFLOW overflow_behavior])
5969            if self._match_text_seq("ERROR"):
5970                on_overflow: t.Optional[exp.Expression] = exp.var("ERROR")
5971            else:
5972                self._match_text_seq("TRUNCATE")
5973                on_overflow = self.expression(
5974                    exp.OverflowTruncateBehavior,
5975                    this=self._parse_string(),
5976                    with_count=(
5977                        self._match_text_seq("WITH", "COUNT")
5978                        or not self._match_text_seq("WITHOUT", "COUNT")
5979                    ),
5980                )
5981        else:
5982            on_overflow = None
5983
5984        index = self._index
5985        if not self._match(TokenType.R_PAREN) and args:
5986            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
5987            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
5988            args[-1] = self._parse_limit(this=self._parse_order(this=args[-1]))
5989            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
5990
5991        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
5992        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
5993        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
5994        if not self._match_text_seq("WITHIN", "GROUP"):
5995            self._retreat(index)
5996            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
5997
5998        # The corresponding match_r_paren will be called in parse_function (caller)
5999        self._match_l_paren()
6000
6001        return self.expression(
6002            exp.GroupConcat,
6003            this=self._parse_order(this=seq_get(args, 0)),
6004            separator=seq_get(args, 1),
6005            on_overflow=on_overflow,
6006        )
6007
6008    def _parse_convert(
6009        self, strict: bool, safe: t.Optional[bool] = None
6010    ) -> t.Optional[exp.Expression]:
6011        this = self._parse_bitwise()
6012
6013        if self._match(TokenType.USING):
6014            to: t.Optional[exp.Expression] = self.expression(
6015                exp.CharacterSet, this=self._parse_var()
6016            )
6017        elif self._match(TokenType.COMMA):
6018            to = self._parse_types()
6019        else:
6020            to = None
6021
6022        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
6023
6024    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
6025        """
6026        There are generally two variants of the DECODE function:
6027
6028        - DECODE(bin, charset)
6029        - DECODE(expression, search, result [, search, result] ... [, default])
6030
6031        The second variant will always be parsed into a CASE expression. Note that NULL
6032        needs special treatment, since we need to explicitly check for it with `IS NULL`,
6033        instead of relying on pattern matching.
6034        """
6035        args = self._parse_csv(self._parse_assignment)
6036
6037        if len(args) < 3:
6038            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
6039
6040        expression, *expressions = args
6041        if not expression:
6042            return None
6043
6044        ifs = []
6045        for search, result in zip(expressions[::2], expressions[1::2]):
6046            if not search or not result:
6047                return None
6048
6049            if isinstance(search, exp.Literal):
6050                ifs.append(
6051                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
6052                )
6053            elif isinstance(search, exp.Null):
6054                ifs.append(
6055                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
6056                )
6057            else:
6058                cond = exp.or_(
6059                    exp.EQ(this=expression.copy(), expression=search),
6060                    exp.and_(
6061                        exp.Is(this=expression.copy(), expression=exp.Null()),
6062                        exp.Is(this=search.copy(), expression=exp.Null()),
6063                        copy=False,
6064                    ),
6065                    copy=False,
6066                )
6067                ifs.append(exp.If(this=cond, true=result))
6068
6069        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
6070
6071    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
6072        self._match_text_seq("KEY")
6073        key = self._parse_column()
6074        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
6075        self._match_text_seq("VALUE")
6076        value = self._parse_bitwise()
6077
6078        if not key and not value:
6079            return None
6080        return self.expression(exp.JSONKeyValue, this=key, expression=value)
6081
6082    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
6083        if not this or not self._match_text_seq("FORMAT", "JSON"):
6084            return this
6085
6086        return self.expression(exp.FormatJson, this=this)
6087
6088    def _parse_on_condition(self) -> t.Optional[exp.OnCondition]:
6089        # MySQL uses "X ON EMPTY Y ON ERROR" (e.g. JSON_VALUE) while Oracle uses the opposite (e.g. JSON_EXISTS)
6090        if self.dialect.ON_CONDITION_EMPTY_BEFORE_ERROR:
6091            empty = self._parse_on_handling("EMPTY", *self.ON_CONDITION_TOKENS)
6092            error = self._parse_on_handling("ERROR", *self.ON_CONDITION_TOKENS)
6093        else:
6094            error = self._parse_on_handling("ERROR", *self.ON_CONDITION_TOKENS)
6095            empty = self._parse_on_handling("EMPTY", *self.ON_CONDITION_TOKENS)
6096
6097        null = self._parse_on_handling("NULL", *self.ON_CONDITION_TOKENS)
6098
6099        if not empty and not error and not null:
6100            return None
6101
6102        return self.expression(
6103            exp.OnCondition,
6104            empty=empty,
6105            error=error,
6106            null=null,
6107        )
6108
6109    def _parse_on_handling(
6110        self, on: str, *values: str
6111    ) -> t.Optional[str] | t.Optional[exp.Expression]:
6112        # Parses the "X ON Y" or "DEFAULT <expr> ON Y syntax, e.g. NULL ON NULL (Oracle, T-SQL, MySQL)
6113        for value in values:
6114            if self._match_text_seq(value, "ON", on):
6115                return f"{value} ON {on}"
6116
6117        index = self._index
6118        if self._match(TokenType.DEFAULT):
6119            default_value = self._parse_bitwise()
6120            if self._match_text_seq("ON", on):
6121                return default_value
6122
6123            self._retreat(index)
6124
6125        return None
6126
6127    @t.overload
6128    def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
6129
6130    @t.overload
6131    def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
6132
6133    def _parse_json_object(self, agg=False):
6134        star = self._parse_star()
6135        expressions = (
6136            [star]
6137            if star
6138            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
6139        )
6140        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
6141
6142        unique_keys = None
6143        if self._match_text_seq("WITH", "UNIQUE"):
6144            unique_keys = True
6145        elif self._match_text_seq("WITHOUT", "UNIQUE"):
6146            unique_keys = False
6147
6148        self._match_text_seq("KEYS")
6149
6150        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
6151            self._parse_type()
6152        )
6153        encoding = self._match_text_seq("ENCODING") and self._parse_var()
6154
6155        return self.expression(
6156            exp.JSONObjectAgg if agg else exp.JSONObject,
6157            expressions=expressions,
6158            null_handling=null_handling,
6159            unique_keys=unique_keys,
6160            return_type=return_type,
6161            encoding=encoding,
6162        )
6163
6164    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
6165    def _parse_json_column_def(self) -> exp.JSONColumnDef:
6166        if not self._match_text_seq("NESTED"):
6167            this = self._parse_id_var()
6168            kind = self._parse_types(allow_identifiers=False)
6169            nested = None
6170        else:
6171            this = None
6172            kind = None
6173            nested = True
6174
6175        path = self._match_text_seq("PATH") and self._parse_string()
6176        nested_schema = nested and self._parse_json_schema()
6177
6178        return self.expression(
6179            exp.JSONColumnDef,
6180            this=this,
6181            kind=kind,
6182            path=path,
6183            nested_schema=nested_schema,
6184        )
6185
6186    def _parse_json_schema(self) -> exp.JSONSchema:
6187        self._match_text_seq("COLUMNS")
6188        return self.expression(
6189            exp.JSONSchema,
6190            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
6191        )
6192
6193    def _parse_json_table(self) -> exp.JSONTable:
6194        this = self._parse_format_json(self._parse_bitwise())
6195        path = self._match(TokenType.COMMA) and self._parse_string()
6196        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
6197        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
6198        schema = self._parse_json_schema()
6199
6200        return exp.JSONTable(
6201            this=this,
6202            schema=schema,
6203            path=path,
6204            error_handling=error_handling,
6205            empty_handling=empty_handling,
6206        )
6207
6208    def _parse_match_against(self) -> exp.MatchAgainst:
6209        expressions = self._parse_csv(self._parse_column)
6210
6211        self._match_text_seq(")", "AGAINST", "(")
6212
6213        this = self._parse_string()
6214
6215        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
6216            modifier = "IN NATURAL LANGUAGE MODE"
6217            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
6218                modifier = f"{modifier} WITH QUERY EXPANSION"
6219        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
6220            modifier = "IN BOOLEAN MODE"
6221        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
6222            modifier = "WITH QUERY EXPANSION"
6223        else:
6224            modifier = None
6225
6226        return self.expression(
6227            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
6228        )
6229
6230    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
6231    def _parse_open_json(self) -> exp.OpenJSON:
6232        this = self._parse_bitwise()
6233        path = self._match(TokenType.COMMA) and self._parse_string()
6234
6235        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
6236            this = self._parse_field(any_token=True)
6237            kind = self._parse_types()
6238            path = self._parse_string()
6239            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
6240
6241            return self.expression(
6242                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
6243            )
6244
6245        expressions = None
6246        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
6247            self._match_l_paren()
6248            expressions = self._parse_csv(_parse_open_json_column_def)
6249
6250        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
6251
6252    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
6253        args = self._parse_csv(self._parse_bitwise)
6254
6255        if self._match(TokenType.IN):
6256            return self.expression(
6257                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
6258            )
6259
6260        if haystack_first:
6261            haystack = seq_get(args, 0)
6262            needle = seq_get(args, 1)
6263        else:
6264            needle = seq_get(args, 0)
6265            haystack = seq_get(args, 1)
6266
6267        return self.expression(
6268            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
6269        )
6270
6271    def _parse_predict(self) -> exp.Predict:
6272        self._match_text_seq("MODEL")
6273        this = self._parse_table()
6274
6275        self._match(TokenType.COMMA)
6276        self._match_text_seq("TABLE")
6277
6278        return self.expression(
6279            exp.Predict,
6280            this=this,
6281            expression=self._parse_table(),
6282            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
6283        )
6284
6285    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
6286        args = self._parse_csv(self._parse_table)
6287        return exp.JoinHint(this=func_name.upper(), expressions=args)
6288
6289    def _parse_substring(self) -> exp.Substring:
6290        # Postgres supports the form: substring(string [from int] [for int])
6291        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
6292
6293        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
6294
6295        if self._match(TokenType.FROM):
6296            args.append(self._parse_bitwise())
6297        if self._match(TokenType.FOR):
6298            if len(args) == 1:
6299                args.append(exp.Literal.number(1))
6300            args.append(self._parse_bitwise())
6301
6302        return self.validate_expression(exp.Substring.from_arg_list(args), args)
6303
6304    def _parse_trim(self) -> exp.Trim:
6305        # https://www.w3resource.com/sql/character-functions/trim.php
6306        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
6307
6308        position = None
6309        collation = None
6310        expression = None
6311
6312        if self._match_texts(self.TRIM_TYPES):
6313            position = self._prev.text.upper()
6314
6315        this = self._parse_bitwise()
6316        if self._match_set((TokenType.FROM, TokenType.COMMA)):
6317            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
6318            expression = self._parse_bitwise()
6319
6320            if invert_order:
6321                this, expression = expression, this
6322
6323        if self._match(TokenType.COLLATE):
6324            collation = self._parse_bitwise()
6325
6326        return self.expression(
6327            exp.Trim, this=this, position=position, expression=expression, collation=collation
6328        )
6329
6330    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
6331        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
6332
6333    def _parse_named_window(self) -> t.Optional[exp.Expression]:
6334        return self._parse_window(self._parse_id_var(), alias=True)
6335
6336    def _parse_respect_or_ignore_nulls(
6337        self, this: t.Optional[exp.Expression]
6338    ) -> t.Optional[exp.Expression]:
6339        if self._match_text_seq("IGNORE", "NULLS"):
6340            return self.expression(exp.IgnoreNulls, this=this)
6341        if self._match_text_seq("RESPECT", "NULLS"):
6342            return self.expression(exp.RespectNulls, this=this)
6343        return this
6344
6345    def _parse_having_max(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
6346        if self._match(TokenType.HAVING):
6347            self._match_texts(("MAX", "MIN"))
6348            max = self._prev.text.upper() != "MIN"
6349            return self.expression(
6350                exp.HavingMax, this=this, expression=self._parse_column(), max=max
6351            )
6352
6353        return this
6354
6355    def _parse_window(
6356        self, this: t.Optional[exp.Expression], alias: bool = False
6357    ) -> t.Optional[exp.Expression]:
6358        func = this
6359        comments = func.comments if isinstance(func, exp.Expression) else None
6360
6361        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
6362            self._match(TokenType.WHERE)
6363            this = self.expression(
6364                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
6365            )
6366            self._match_r_paren()
6367
6368        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
6369        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
6370        if self._match_text_seq("WITHIN", "GROUP"):
6371            order = self._parse_wrapped(self._parse_order)
6372            this = self.expression(exp.WithinGroup, this=this, expression=order)
6373
6374        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
6375        # Some dialects choose to implement and some do not.
6376        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
6377
6378        # There is some code above in _parse_lambda that handles
6379        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
6380
6381        # The below changes handle
6382        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
6383
6384        # Oracle allows both formats
6385        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
6386        #   and Snowflake chose to do the same for familiarity
6387        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
6388        if isinstance(this, exp.AggFunc):
6389            ignore_respect = this.find(exp.IgnoreNulls, exp.RespectNulls)
6390
6391            if ignore_respect and ignore_respect is not this:
6392                ignore_respect.replace(ignore_respect.this)
6393                this = self.expression(ignore_respect.__class__, this=this)
6394
6395        this = self._parse_respect_or_ignore_nulls(this)
6396
6397        # bigquery select from window x AS (partition by ...)
6398        if alias:
6399            over = None
6400            self._match(TokenType.ALIAS)
6401        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
6402            return this
6403        else:
6404            over = self._prev.text.upper()
6405
6406        if comments and isinstance(func, exp.Expression):
6407            func.pop_comments()
6408
6409        if not self._match(TokenType.L_PAREN):
6410            return self.expression(
6411                exp.Window,
6412                comments=comments,
6413                this=this,
6414                alias=self._parse_id_var(False),
6415                over=over,
6416            )
6417
6418        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
6419
6420        first = self._match(TokenType.FIRST)
6421        if self._match_text_seq("LAST"):
6422            first = False
6423
6424        partition, order = self._parse_partition_and_order()
6425        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
6426
6427        if kind:
6428            self._match(TokenType.BETWEEN)
6429            start = self._parse_window_spec()
6430            self._match(TokenType.AND)
6431            end = self._parse_window_spec()
6432
6433            spec = self.expression(
6434                exp.WindowSpec,
6435                kind=kind,
6436                start=start["value"],
6437                start_side=start["side"],
6438                end=end["value"],
6439                end_side=end["side"],
6440            )
6441        else:
6442            spec = None
6443
6444        self._match_r_paren()
6445
6446        window = self.expression(
6447            exp.Window,
6448            comments=comments,
6449            this=this,
6450            partition_by=partition,
6451            order=order,
6452            spec=spec,
6453            alias=window_alias,
6454            over=over,
6455            first=first,
6456        )
6457
6458        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
6459        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
6460            return self._parse_window(window, alias=alias)
6461
6462        return window
6463
6464    def _parse_partition_and_order(
6465        self,
6466    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
6467        return self._parse_partition_by(), self._parse_order()
6468
6469    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
6470        self._match(TokenType.BETWEEN)
6471
6472        return {
6473            "value": (
6474                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
6475                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
6476                or self._parse_bitwise()
6477            ),
6478            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
6479        }
6480
6481    def _parse_alias(
6482        self, this: t.Optional[exp.Expression], explicit: bool = False
6483    ) -> t.Optional[exp.Expression]:
6484        any_token = self._match(TokenType.ALIAS)
6485        comments = self._prev_comments or []
6486
6487        if explicit and not any_token:
6488            return this
6489
6490        if self._match(TokenType.L_PAREN):
6491            aliases = self.expression(
6492                exp.Aliases,
6493                comments=comments,
6494                this=this,
6495                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
6496            )
6497            self._match_r_paren(aliases)
6498            return aliases
6499
6500        alias = self._parse_id_var(any_token, tokens=self.ALIAS_TOKENS) or (
6501            self.STRING_ALIASES and self._parse_string_as_identifier()
6502        )
6503
6504        if alias:
6505            comments.extend(alias.pop_comments())
6506            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
6507            column = this.this
6508
6509            # Moves the comment next to the alias in `expr /* comment */ AS alias`
6510            if not this.comments and column and column.comments:
6511                this.comments = column.pop_comments()
6512
6513        return this
6514
6515    def _parse_id_var(
6516        self,
6517        any_token: bool = True,
6518        tokens: t.Optional[t.Collection[TokenType]] = None,
6519    ) -> t.Optional[exp.Expression]:
6520        expression = self._parse_identifier()
6521        if not expression and (
6522            (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS)
6523        ):
6524            quoted = self._prev.token_type == TokenType.STRING
6525            expression = self.expression(exp.Identifier, this=self._prev.text, quoted=quoted)
6526
6527        return expression
6528
6529    def _parse_string(self) -> t.Optional[exp.Expression]:
6530        if self._match_set(self.STRING_PARSERS):
6531            return self.STRING_PARSERS[self._prev.token_type](self, self._prev)
6532        return self._parse_placeholder()
6533
6534    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
6535        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
6536
6537    def _parse_number(self) -> t.Optional[exp.Expression]:
6538        if self._match_set(self.NUMERIC_PARSERS):
6539            return self.NUMERIC_PARSERS[self._prev.token_type](self, self._prev)
6540        return self._parse_placeholder()
6541
6542    def _parse_identifier(self) -> t.Optional[exp.Expression]:
6543        if self._match(TokenType.IDENTIFIER):
6544            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
6545        return self._parse_placeholder()
6546
6547    def _parse_var(
6548        self,
6549        any_token: bool = False,
6550        tokens: t.Optional[t.Collection[TokenType]] = None,
6551        upper: bool = False,
6552    ) -> t.Optional[exp.Expression]:
6553        if (
6554            (any_token and self._advance_any())
6555            or self._match(TokenType.VAR)
6556            or (self._match_set(tokens) if tokens else False)
6557        ):
6558            return self.expression(
6559                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
6560            )
6561        return self._parse_placeholder()
6562
6563    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
6564        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
6565            self._advance()
6566            return self._prev
6567        return None
6568
6569    def _parse_var_or_string(self, upper: bool = False) -> t.Optional[exp.Expression]:
6570        return self._parse_string() or self._parse_var(any_token=True, upper=upper)
6571
6572    def _parse_primary_or_var(self) -> t.Optional[exp.Expression]:
6573        return self._parse_primary() or self._parse_var(any_token=True)
6574
6575    def _parse_null(self) -> t.Optional[exp.Expression]:
6576        if self._match_set(self.NULL_TOKENS):
6577            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
6578        return self._parse_placeholder()
6579
6580    def _parse_boolean(self) -> t.Optional[exp.Expression]:
6581        if self._match(TokenType.TRUE):
6582            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
6583        if self._match(TokenType.FALSE):
6584            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
6585        return self._parse_placeholder()
6586
6587    def _parse_star(self) -> t.Optional[exp.Expression]:
6588        if self._match(TokenType.STAR):
6589            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
6590        return self._parse_placeholder()
6591
6592    def _parse_parameter(self) -> exp.Parameter:
6593        this = self._parse_identifier() or self._parse_primary_or_var()
6594        return self.expression(exp.Parameter, this=this)
6595
6596    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
6597        if self._match_set(self.PLACEHOLDER_PARSERS):
6598            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
6599            if placeholder:
6600                return placeholder
6601            self._advance(-1)
6602        return None
6603
6604    def _parse_star_op(self, *keywords: str) -> t.Optional[t.List[exp.Expression]]:
6605        if not self._match_texts(keywords):
6606            return None
6607        if self._match(TokenType.L_PAREN, advance=False):
6608            return self._parse_wrapped_csv(self._parse_expression)
6609
6610        expression = self._parse_expression()
6611        return [expression] if expression else None
6612
6613    def _parse_csv(
6614        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
6615    ) -> t.List[exp.Expression]:
6616        parse_result = parse_method()
6617        items = [parse_result] if parse_result is not None else []
6618
6619        while self._match(sep):
6620            self._add_comments(parse_result)
6621            parse_result = parse_method()
6622            if parse_result is not None:
6623                items.append(parse_result)
6624
6625        return items
6626
6627    def _parse_tokens(
6628        self, parse_method: t.Callable, expressions: t.Dict
6629    ) -> t.Optional[exp.Expression]:
6630        this = parse_method()
6631
6632        while self._match_set(expressions):
6633            this = self.expression(
6634                expressions[self._prev.token_type],
6635                this=this,
6636                comments=self._prev_comments,
6637                expression=parse_method(),
6638            )
6639
6640        return this
6641
6642    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
6643        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
6644
6645    def _parse_wrapped_csv(
6646        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
6647    ) -> t.List[exp.Expression]:
6648        return self._parse_wrapped(
6649            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
6650        )
6651
6652    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
6653        wrapped = self._match(TokenType.L_PAREN)
6654        if not wrapped and not optional:
6655            self.raise_error("Expecting (")
6656        parse_result = parse_method()
6657        if wrapped:
6658            self._match_r_paren()
6659        return parse_result
6660
6661    def _parse_expressions(self) -> t.List[exp.Expression]:
6662        return self._parse_csv(self._parse_expression)
6663
6664    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
6665        return self._parse_select() or self._parse_set_operations(
6666            self._parse_expression() if alias else self._parse_assignment()
6667        )
6668
6669    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
6670        return self._parse_query_modifiers(
6671            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
6672        )
6673
6674    def _parse_transaction(self) -> exp.Transaction | exp.Command:
6675        this = None
6676        if self._match_texts(self.TRANSACTION_KIND):
6677            this = self._prev.text
6678
6679        self._match_texts(("TRANSACTION", "WORK"))
6680
6681        modes = []
6682        while True:
6683            mode = []
6684            while self._match(TokenType.VAR):
6685                mode.append(self._prev.text)
6686
6687            if mode:
6688                modes.append(" ".join(mode))
6689            if not self._match(TokenType.COMMA):
6690                break
6691
6692        return self.expression(exp.Transaction, this=this, modes=modes)
6693
6694    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
6695        chain = None
6696        savepoint = None
6697        is_rollback = self._prev.token_type == TokenType.ROLLBACK
6698
6699        self._match_texts(("TRANSACTION", "WORK"))
6700
6701        if self._match_text_seq("TO"):
6702            self._match_text_seq("SAVEPOINT")
6703            savepoint = self._parse_id_var()
6704
6705        if self._match(TokenType.AND):
6706            chain = not self._match_text_seq("NO")
6707            self._match_text_seq("CHAIN")
6708
6709        if is_rollback:
6710            return self.expression(exp.Rollback, savepoint=savepoint)
6711
6712        return self.expression(exp.Commit, chain=chain)
6713
6714    def _parse_refresh(self) -> exp.Refresh:
6715        self._match(TokenType.TABLE)
6716        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
6717
6718    def _parse_add_column(self) -> t.Optional[exp.Expression]:
6719        if not self._match_text_seq("ADD"):
6720            return None
6721
6722        self._match(TokenType.COLUMN)
6723        exists_column = self._parse_exists(not_=True)
6724        expression = self._parse_field_def()
6725
6726        if expression:
6727            expression.set("exists", exists_column)
6728
6729            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
6730            if self._match_texts(("FIRST", "AFTER")):
6731                position = self._prev.text
6732                column_position = self.expression(
6733                    exp.ColumnPosition, this=self._parse_column(), position=position
6734                )
6735                expression.set("position", column_position)
6736
6737        return expression
6738
6739    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
6740        drop = self._match(TokenType.DROP) and self._parse_drop()
6741        if drop and not isinstance(drop, exp.Command):
6742            drop.set("kind", drop.args.get("kind", "COLUMN"))
6743        return drop
6744
6745    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
6746    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
6747        return self.expression(
6748            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
6749        )
6750
6751    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
6752        index = self._index - 1
6753
6754        if self._match_set(self.ADD_CONSTRAINT_TOKENS, advance=False):
6755            return self._parse_csv(
6756                lambda: self.expression(
6757                    exp.AddConstraint, expressions=self._parse_csv(self._parse_constraint)
6758                )
6759            )
6760
6761        self._retreat(index)
6762        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
6763            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
6764
6765        if self._match_text_seq("ADD", "COLUMNS"):
6766            schema = self._parse_schema()
6767            if schema:
6768                return [schema]
6769            return []
6770
6771        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
6772
6773    def _parse_alter_table_alter(self) -> t.Optional[exp.Expression]:
6774        if self._match_texts(self.ALTER_ALTER_PARSERS):
6775            return self.ALTER_ALTER_PARSERS[self._prev.text.upper()](self)
6776
6777        # Many dialects support the ALTER [COLUMN] syntax, so if there is no
6778        # keyword after ALTER we default to parsing this statement
6779        self._match(TokenType.COLUMN)
6780        column = self._parse_field(any_token=True)
6781
6782        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
6783            return self.expression(exp.AlterColumn, this=column, drop=True)
6784        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
6785            return self.expression(exp.AlterColumn, this=column, default=self._parse_assignment())
6786        if self._match(TokenType.COMMENT):
6787            return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
6788        if self._match_text_seq("DROP", "NOT", "NULL"):
6789            return self.expression(
6790                exp.AlterColumn,
6791                this=column,
6792                drop=True,
6793                allow_null=True,
6794            )
6795        if self._match_text_seq("SET", "NOT", "NULL"):
6796            return self.expression(
6797                exp.AlterColumn,
6798                this=column,
6799                allow_null=False,
6800            )
6801        self._match_text_seq("SET", "DATA")
6802        self._match_text_seq("TYPE")
6803        return self.expression(
6804            exp.AlterColumn,
6805            this=column,
6806            dtype=self._parse_types(),
6807            collate=self._match(TokenType.COLLATE) and self._parse_term(),
6808            using=self._match(TokenType.USING) and self._parse_assignment(),
6809        )
6810
6811    def _parse_alter_diststyle(self) -> exp.AlterDistStyle:
6812        if self._match_texts(("ALL", "EVEN", "AUTO")):
6813            return self.expression(exp.AlterDistStyle, this=exp.var(self._prev.text.upper()))
6814
6815        self._match_text_seq("KEY", "DISTKEY")
6816        return self.expression(exp.AlterDistStyle, this=self._parse_column())
6817
6818    def _parse_alter_sortkey(self, compound: t.Optional[bool] = None) -> exp.AlterSortKey:
6819        if compound:
6820            self._match_text_seq("SORTKEY")
6821
6822        if self._match(TokenType.L_PAREN, advance=False):
6823            return self.expression(
6824                exp.AlterSortKey, expressions=self._parse_wrapped_id_vars(), compound=compound
6825            )
6826
6827        self._match_texts(("AUTO", "NONE"))
6828        return self.expression(
6829            exp.AlterSortKey, this=exp.var(self._prev.text.upper()), compound=compound
6830        )
6831
6832    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
6833        index = self._index - 1
6834
6835        partition_exists = self._parse_exists()
6836        if self._match(TokenType.PARTITION, advance=False):
6837            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
6838
6839        self._retreat(index)
6840        return self._parse_csv(self._parse_drop_column)
6841
6842    def _parse_alter_table_rename(self) -> t.Optional[exp.AlterRename | exp.RenameColumn]:
6843        if self._match(TokenType.COLUMN):
6844            exists = self._parse_exists()
6845            old_column = self._parse_column()
6846            to = self._match_text_seq("TO")
6847            new_column = self._parse_column()
6848
6849            if old_column is None or to is None or new_column is None:
6850                return None
6851
6852            return self.expression(exp.RenameColumn, this=old_column, to=new_column, exists=exists)
6853
6854        self._match_text_seq("TO")
6855        return self.expression(exp.AlterRename, this=self._parse_table(schema=True))
6856
6857    def _parse_alter_table_set(self) -> exp.AlterSet:
6858        alter_set = self.expression(exp.AlterSet)
6859
6860        if self._match(TokenType.L_PAREN, advance=False) or self._match_text_seq(
6861            "TABLE", "PROPERTIES"
6862        ):
6863            alter_set.set("expressions", self._parse_wrapped_csv(self._parse_assignment))
6864        elif self._match_text_seq("FILESTREAM_ON", advance=False):
6865            alter_set.set("expressions", [self._parse_assignment()])
6866        elif self._match_texts(("LOGGED", "UNLOGGED")):
6867            alter_set.set("option", exp.var(self._prev.text.upper()))
6868        elif self._match_text_seq("WITHOUT") and self._match_texts(("CLUSTER", "OIDS")):
6869            alter_set.set("option", exp.var(f"WITHOUT {self._prev.text.upper()}"))
6870        elif self._match_text_seq("LOCATION"):
6871            alter_set.set("location", self._parse_field())
6872        elif self._match_text_seq("ACCESS", "METHOD"):
6873            alter_set.set("access_method", self._parse_field())
6874        elif self._match_text_seq("TABLESPACE"):
6875            alter_set.set("tablespace", self._parse_field())
6876        elif self._match_text_seq("FILE", "FORMAT") or self._match_text_seq("FILEFORMAT"):
6877            alter_set.set("file_format", [self._parse_field()])
6878        elif self._match_text_seq("STAGE_FILE_FORMAT"):
6879            alter_set.set("file_format", self._parse_wrapped_options())
6880        elif self._match_text_seq("STAGE_COPY_OPTIONS"):
6881            alter_set.set("copy_options", self._parse_wrapped_options())
6882        elif self._match_text_seq("TAG") or self._match_text_seq("TAGS"):
6883            alter_set.set("tag", self._parse_csv(self._parse_assignment))
6884        else:
6885            if self._match_text_seq("SERDE"):
6886                alter_set.set("serde", self._parse_field())
6887
6888            alter_set.set("expressions", [self._parse_properties()])
6889
6890        return alter_set
6891
6892    def _parse_alter(self) -> exp.Alter | exp.Command:
6893        start = self._prev
6894
6895        alter_token = self._match_set(self.ALTERABLES) and self._prev
6896        if not alter_token:
6897            return self._parse_as_command(start)
6898
6899        exists = self._parse_exists()
6900        only = self._match_text_seq("ONLY")
6901        this = self._parse_table(schema=True)
6902        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
6903
6904        if self._next:
6905            self._advance()
6906
6907        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
6908        if parser:
6909            actions = ensure_list(parser(self))
6910            not_valid = self._match_text_seq("NOT", "VALID")
6911            options = self._parse_csv(self._parse_property)
6912
6913            if not self._curr and actions:
6914                return self.expression(
6915                    exp.Alter,
6916                    this=this,
6917                    kind=alter_token.text.upper(),
6918                    exists=exists,
6919                    actions=actions,
6920                    only=only,
6921                    options=options,
6922                    cluster=cluster,
6923                    not_valid=not_valid,
6924                )
6925
6926        return self._parse_as_command(start)
6927
6928    def _parse_merge(self) -> exp.Merge:
6929        self._match(TokenType.INTO)
6930        target = self._parse_table()
6931
6932        if target and self._match(TokenType.ALIAS, advance=False):
6933            target.set("alias", self._parse_table_alias())
6934
6935        self._match(TokenType.USING)
6936        using = self._parse_table()
6937
6938        self._match(TokenType.ON)
6939        on = self._parse_assignment()
6940
6941        return self.expression(
6942            exp.Merge,
6943            this=target,
6944            using=using,
6945            on=on,
6946            expressions=self._parse_when_matched(),
6947            returning=self._parse_returning(),
6948        )
6949
6950    def _parse_when_matched(self) -> t.List[exp.When]:
6951        whens = []
6952
6953        while self._match(TokenType.WHEN):
6954            matched = not self._match(TokenType.NOT)
6955            self._match_text_seq("MATCHED")
6956            source = (
6957                False
6958                if self._match_text_seq("BY", "TARGET")
6959                else self._match_text_seq("BY", "SOURCE")
6960            )
6961            condition = self._parse_assignment() if self._match(TokenType.AND) else None
6962
6963            self._match(TokenType.THEN)
6964
6965            if self._match(TokenType.INSERT):
6966                this = self._parse_star()
6967                if this:
6968                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=this)
6969                else:
6970                    then = self.expression(
6971                        exp.Insert,
6972                        this=exp.var("ROW") if self._match_text_seq("ROW") else self._parse_value(),
6973                        expression=self._match_text_seq("VALUES") and self._parse_value(),
6974                    )
6975            elif self._match(TokenType.UPDATE):
6976                expressions = self._parse_star()
6977                if expressions:
6978                    then = self.expression(exp.Update, expressions=expressions)
6979                else:
6980                    then = self.expression(
6981                        exp.Update,
6982                        expressions=self._match(TokenType.SET)
6983                        and self._parse_csv(self._parse_equality),
6984                    )
6985            elif self._match(TokenType.DELETE):
6986                then = self.expression(exp.Var, this=self._prev.text)
6987            else:
6988                then = self._parse_var_from_options(self.CONFLICT_ACTIONS)
6989
6990            whens.append(
6991                self.expression(
6992                    exp.When,
6993                    matched=matched,
6994                    source=source,
6995                    condition=condition,
6996                    then=then,
6997                )
6998            )
6999        return whens
7000
7001    def _parse_show(self) -> t.Optional[exp.Expression]:
7002        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
7003        if parser:
7004            return parser(self)
7005        return self._parse_as_command(self._prev)
7006
7007    def _parse_set_item_assignment(
7008        self, kind: t.Optional[str] = None
7009    ) -> t.Optional[exp.Expression]:
7010        index = self._index
7011
7012        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
7013            return self._parse_set_transaction(global_=kind == "GLOBAL")
7014
7015        left = self._parse_primary() or self._parse_column()
7016        assignment_delimiter = self._match_texts(("=", "TO"))
7017
7018        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
7019            self._retreat(index)
7020            return None
7021
7022        right = self._parse_statement() or self._parse_id_var()
7023        if isinstance(right, (exp.Column, exp.Identifier)):
7024            right = exp.var(right.name)
7025
7026        this = self.expression(exp.EQ, this=left, expression=right)
7027        return self.expression(exp.SetItem, this=this, kind=kind)
7028
7029    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
7030        self._match_text_seq("TRANSACTION")
7031        characteristics = self._parse_csv(
7032            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
7033        )
7034        return self.expression(
7035            exp.SetItem,
7036            expressions=characteristics,
7037            kind="TRANSACTION",
7038            **{"global": global_},  # type: ignore
7039        )
7040
7041    def _parse_set_item(self) -> t.Optional[exp.Expression]:
7042        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
7043        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
7044
7045    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
7046        index = self._index
7047        set_ = self.expression(
7048            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
7049        )
7050
7051        if self._curr:
7052            self._retreat(index)
7053            return self._parse_as_command(self._prev)
7054
7055        return set_
7056
7057    def _parse_var_from_options(
7058        self, options: OPTIONS_TYPE, raise_unmatched: bool = True
7059    ) -> t.Optional[exp.Var]:
7060        start = self._curr
7061        if not start:
7062            return None
7063
7064        option = start.text.upper()
7065        continuations = options.get(option)
7066
7067        index = self._index
7068        self._advance()
7069        for keywords in continuations or []:
7070            if isinstance(keywords, str):
7071                keywords = (keywords,)
7072
7073            if self._match_text_seq(*keywords):
7074                option = f"{option} {' '.join(keywords)}"
7075                break
7076        else:
7077            if continuations or continuations is None:
7078                if raise_unmatched:
7079                    self.raise_error(f"Unknown option {option}")
7080
7081                self._retreat(index)
7082                return None
7083
7084        return exp.var(option)
7085
7086    def _parse_as_command(self, start: Token) -> exp.Command:
7087        while self._curr:
7088            self._advance()
7089        text = self._find_sql(start, self._prev)
7090        size = len(start.text)
7091        self._warn_unsupported()
7092        return exp.Command(this=text[:size], expression=text[size:])
7093
7094    def _parse_dict_property(self, this: str) -> exp.DictProperty:
7095        settings = []
7096
7097        self._match_l_paren()
7098        kind = self._parse_id_var()
7099
7100        if self._match(TokenType.L_PAREN):
7101            while True:
7102                key = self._parse_id_var()
7103                value = self._parse_primary()
7104
7105                if not key and value is None:
7106                    break
7107                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
7108            self._match(TokenType.R_PAREN)
7109
7110        self._match_r_paren()
7111
7112        return self.expression(
7113            exp.DictProperty,
7114            this=this,
7115            kind=kind.this if kind else None,
7116            settings=settings,
7117        )
7118
7119    def _parse_dict_range(self, this: str) -> exp.DictRange:
7120        self._match_l_paren()
7121        has_min = self._match_text_seq("MIN")
7122        if has_min:
7123            min = self._parse_var() or self._parse_primary()
7124            self._match_text_seq("MAX")
7125            max = self._parse_var() or self._parse_primary()
7126        else:
7127            max = self._parse_var() or self._parse_primary()
7128            min = exp.Literal.number(0)
7129        self._match_r_paren()
7130        return self.expression(exp.DictRange, this=this, min=min, max=max)
7131
7132    def _parse_comprehension(
7133        self, this: t.Optional[exp.Expression]
7134    ) -> t.Optional[exp.Comprehension]:
7135        index = self._index
7136        expression = self._parse_column()
7137        if not self._match(TokenType.IN):
7138            self._retreat(index - 1)
7139            return None
7140        iterator = self._parse_column()
7141        condition = self._parse_assignment() if self._match_text_seq("IF") else None
7142        return self.expression(
7143            exp.Comprehension,
7144            this=this,
7145            expression=expression,
7146            iterator=iterator,
7147            condition=condition,
7148        )
7149
7150    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
7151        if self._match(TokenType.HEREDOC_STRING):
7152            return self.expression(exp.Heredoc, this=self._prev.text)
7153
7154        if not self._match_text_seq("$"):
7155            return None
7156
7157        tags = ["$"]
7158        tag_text = None
7159
7160        if self._is_connected():
7161            self._advance()
7162            tags.append(self._prev.text.upper())
7163        else:
7164            self.raise_error("No closing $ found")
7165
7166        if tags[-1] != "$":
7167            if self._is_connected() and self._match_text_seq("$"):
7168                tag_text = tags[-1]
7169                tags.append("$")
7170            else:
7171                self.raise_error("No closing $ found")
7172
7173        heredoc_start = self._curr
7174
7175        while self._curr:
7176            if self._match_text_seq(*tags, advance=False):
7177                this = self._find_sql(heredoc_start, self._prev)
7178                self._advance(len(tags))
7179                return self.expression(exp.Heredoc, this=this, tag=tag_text)
7180
7181            self._advance()
7182
7183        self.raise_error(f"No closing {''.join(tags)} found")
7184        return None
7185
7186    def _find_parser(
7187        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
7188    ) -> t.Optional[t.Callable]:
7189        if not self._curr:
7190            return None
7191
7192        index = self._index
7193        this = []
7194        while True:
7195            # The current token might be multiple words
7196            curr = self._curr.text.upper()
7197            key = curr.split(" ")
7198            this.append(curr)
7199
7200            self._advance()
7201            result, trie = in_trie(trie, key)
7202            if result == TrieResult.FAILED:
7203                break
7204
7205            if result == TrieResult.EXISTS:
7206                subparser = parsers[" ".join(this)]
7207                return subparser
7208
7209        self._retreat(index)
7210        return None
7211
7212    def _match(self, token_type, advance=True, expression=None):
7213        if not self._curr:
7214            return None
7215
7216        if self._curr.token_type == token_type:
7217            if advance:
7218                self._advance()
7219            self._add_comments(expression)
7220            return True
7221
7222        return None
7223
7224    def _match_set(self, types, advance=True):
7225        if not self._curr:
7226            return None
7227
7228        if self._curr.token_type in types:
7229            if advance:
7230                self._advance()
7231            return True
7232
7233        return None
7234
7235    def _match_pair(self, token_type_a, token_type_b, advance=True):
7236        if not self._curr or not self._next:
7237            return None
7238
7239        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
7240            if advance:
7241                self._advance(2)
7242            return True
7243
7244        return None
7245
7246    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
7247        if not self._match(TokenType.L_PAREN, expression=expression):
7248            self.raise_error("Expecting (")
7249
7250    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
7251        if not self._match(TokenType.R_PAREN, expression=expression):
7252            self.raise_error("Expecting )")
7253
7254    def _match_texts(self, texts, advance=True):
7255        if (
7256            self._curr
7257            and self._curr.token_type != TokenType.STRING
7258            and self._curr.text.upper() in texts
7259        ):
7260            if advance:
7261                self._advance()
7262            return True
7263        return None
7264
7265    def _match_text_seq(self, *texts, advance=True):
7266        index = self._index
7267        for text in texts:
7268            if (
7269                self._curr
7270                and self._curr.token_type != TokenType.STRING
7271                and self._curr.text.upper() == text
7272            ):
7273                self._advance()
7274            else:
7275                self._retreat(index)
7276                return None
7277
7278        if not advance:
7279            self._retreat(index)
7280
7281        return True
7282
7283    def _replace_lambda(
7284        self, node: t.Optional[exp.Expression], expressions: t.List[exp.Expression]
7285    ) -> t.Optional[exp.Expression]:
7286        if not node:
7287            return node
7288
7289        lambda_types = {e.name: e.args.get("to") or False for e in expressions}
7290
7291        for column in node.find_all(exp.Column):
7292            typ = lambda_types.get(column.parts[0].name)
7293            if typ is not None:
7294                dot_or_id = column.to_dot() if column.table else column.this
7295
7296                if typ:
7297                    dot_or_id = self.expression(
7298                        exp.Cast,
7299                        this=dot_or_id,
7300                        to=typ,
7301                    )
7302
7303                parent = column.parent
7304
7305                while isinstance(parent, exp.Dot):
7306                    if not isinstance(parent.parent, exp.Dot):
7307                        parent.replace(dot_or_id)
7308                        break
7309                    parent = parent.parent
7310                else:
7311                    if column is node:
7312                        node = dot_or_id
7313                    else:
7314                        column.replace(dot_or_id)
7315        return node
7316
7317    def _parse_truncate_table(self) -> t.Optional[exp.TruncateTable] | exp.Expression:
7318        start = self._prev
7319
7320        # Not to be confused with TRUNCATE(number, decimals) function call
7321        if self._match(TokenType.L_PAREN):
7322            self._retreat(self._index - 2)
7323            return self._parse_function()
7324
7325        # Clickhouse supports TRUNCATE DATABASE as well
7326        is_database = self._match(TokenType.DATABASE)
7327
7328        self._match(TokenType.TABLE)
7329
7330        exists = self._parse_exists(not_=False)
7331
7332        expressions = self._parse_csv(
7333            lambda: self._parse_table(schema=True, is_db_reference=is_database)
7334        )
7335
7336        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
7337
7338        if self._match_text_seq("RESTART", "IDENTITY"):
7339            identity = "RESTART"
7340        elif self._match_text_seq("CONTINUE", "IDENTITY"):
7341            identity = "CONTINUE"
7342        else:
7343            identity = None
7344
7345        if self._match_text_seq("CASCADE") or self._match_text_seq("RESTRICT"):
7346            option = self._prev.text
7347        else:
7348            option = None
7349
7350        partition = self._parse_partition()
7351
7352        # Fallback case
7353        if self._curr:
7354            return self._parse_as_command(start)
7355
7356        return self.expression(
7357            exp.TruncateTable,
7358            expressions=expressions,
7359            is_database=is_database,
7360            exists=exists,
7361            cluster=cluster,
7362            identity=identity,
7363            option=option,
7364            partition=partition,
7365        )
7366
7367    def _parse_with_operator(self) -> t.Optional[exp.Expression]:
7368        this = self._parse_ordered(self._parse_opclass)
7369
7370        if not self._match(TokenType.WITH):
7371            return this
7372
7373        op = self._parse_var(any_token=True)
7374
7375        return self.expression(exp.WithOperator, this=this, op=op)
7376
7377    def _parse_wrapped_options(self) -> t.List[t.Optional[exp.Expression]]:
7378        self._match(TokenType.EQ)
7379        self._match(TokenType.L_PAREN)
7380
7381        opts: t.List[t.Optional[exp.Expression]] = []
7382        while self._curr and not self._match(TokenType.R_PAREN):
7383            if self._match_text_seq("FORMAT_NAME", "="):
7384                # The FORMAT_NAME can be set to an identifier for Snowflake and T-SQL,
7385                # so we parse it separately to use _parse_field()
7386                prop = self.expression(
7387                    exp.Property, this=exp.var("FORMAT_NAME"), value=self._parse_field()
7388                )
7389                opts.append(prop)
7390            else:
7391                opts.append(self._parse_property())
7392
7393            self._match(TokenType.COMMA)
7394
7395        return opts
7396
7397    def _parse_copy_parameters(self) -> t.List[exp.CopyParameter]:
7398        sep = TokenType.COMMA if self.dialect.COPY_PARAMS_ARE_CSV else None
7399
7400        options = []
7401        while self._curr and not self._match(TokenType.R_PAREN, advance=False):
7402            option = self._parse_var(any_token=True)
7403            prev = self._prev.text.upper()
7404
7405            # Different dialects might separate options and values by white space, "=" and "AS"
7406            self._match(TokenType.EQ)
7407            self._match(TokenType.ALIAS)
7408
7409            param = self.expression(exp.CopyParameter, this=option)
7410
7411            if prev in self.COPY_INTO_VARLEN_OPTIONS and self._match(
7412                TokenType.L_PAREN, advance=False
7413            ):
7414                # Snowflake FILE_FORMAT case, Databricks COPY & FORMAT options
7415                param.set("expressions", self._parse_wrapped_options())
7416            elif prev == "FILE_FORMAT":
7417                # T-SQL's external file format case
7418                param.set("expression", self._parse_field())
7419            else:
7420                param.set("expression", self._parse_unquoted_field())
7421
7422            options.append(param)
7423            self._match(sep)
7424
7425        return options
7426
7427    def _parse_credentials(self) -> t.Optional[exp.Credentials]:
7428        expr = self.expression(exp.Credentials)
7429
7430        if self._match_text_seq("STORAGE_INTEGRATION", "="):
7431            expr.set("storage", self._parse_field())
7432        if self._match_text_seq("CREDENTIALS"):
7433            # Snowflake case: CREDENTIALS = (...), Redshift case: CREDENTIALS <string>
7434            creds = (
7435                self._parse_wrapped_options() if self._match(TokenType.EQ) else self._parse_field()
7436            )
7437            expr.set("credentials", creds)
7438        if self._match_text_seq("ENCRYPTION"):
7439            expr.set("encryption", self._parse_wrapped_options())
7440        if self._match_text_seq("IAM_ROLE"):
7441            expr.set("iam_role", self._parse_field())
7442        if self._match_text_seq("REGION"):
7443            expr.set("region", self._parse_field())
7444
7445        return expr
7446
7447    def _parse_file_location(self) -> t.Optional[exp.Expression]:
7448        return self._parse_field()
7449
7450    def _parse_copy(self) -> exp.Copy | exp.Command:
7451        start = self._prev
7452
7453        self._match(TokenType.INTO)
7454
7455        this = (
7456            self._parse_select(nested=True, parse_subquery_alias=False)
7457            if self._match(TokenType.L_PAREN, advance=False)
7458            else self._parse_table(schema=True)
7459        )
7460
7461        kind = self._match(TokenType.FROM) or not self._match_text_seq("TO")
7462
7463        files = self._parse_csv(self._parse_file_location)
7464        credentials = self._parse_credentials()
7465
7466        self._match_text_seq("WITH")
7467
7468        params = self._parse_wrapped(self._parse_copy_parameters, optional=True)
7469
7470        # Fallback case
7471        if self._curr:
7472            return self._parse_as_command(start)
7473
7474        return self.expression(
7475            exp.Copy,
7476            this=this,
7477            kind=kind,
7478            credentials=credentials,
7479            files=files,
7480            params=params,
7481        )
7482
7483    def _parse_normalize(self) -> exp.Normalize:
7484        return self.expression(
7485            exp.Normalize,
7486            this=self._parse_bitwise(),
7487            form=self._match(TokenType.COMMA) and self._parse_var(),
7488        )
7489
7490    def _parse_star_ops(self) -> t.Optional[exp.Expression]:
7491        if self._match_text_seq("COLUMNS", "(", advance=False):
7492            this = self._parse_function()
7493            if isinstance(this, exp.Columns):
7494                this.set("unpack", True)
7495            return this
7496
7497        return self.expression(
7498            exp.Star,
7499            **{  # type: ignore
7500                "except": self._parse_star_op("EXCEPT", "EXCLUDE"),
7501                "replace": self._parse_star_op("REPLACE"),
7502                "rename": self._parse_star_op("RENAME"),
7503            },
7504        )
7505
7506    def _parse_grant_privilege(self) -> t.Optional[exp.GrantPrivilege]:
7507        privilege_parts = []
7508
7509        # Keep consuming consecutive keywords until comma (end of this privilege) or ON
7510        # (end of privilege list) or L_PAREN (start of column list) are met
7511        while self._curr and not self._match_set(self.PRIVILEGE_FOLLOW_TOKENS, advance=False):
7512            privilege_parts.append(self._curr.text.upper())
7513            self._advance()
7514
7515        this = exp.var(" ".join(privilege_parts))
7516        expressions = (
7517            self._parse_wrapped_csv(self._parse_column)
7518            if self._match(TokenType.L_PAREN, advance=False)
7519            else None
7520        )
7521
7522        return self.expression(exp.GrantPrivilege, this=this, expressions=expressions)
7523
7524    def _parse_grant_principal(self) -> t.Optional[exp.GrantPrincipal]:
7525        kind = self._match_texts(("ROLE", "GROUP")) and self._prev.text.upper()
7526        principal = self._parse_id_var()
7527
7528        if not principal:
7529            return None
7530
7531        return self.expression(exp.GrantPrincipal, this=principal, kind=kind)
7532
7533    def _parse_grant(self) -> exp.Grant | exp.Command:
7534        start = self._prev
7535
7536        privileges = self._parse_csv(self._parse_grant_privilege)
7537
7538        self._match(TokenType.ON)
7539        kind = self._match_set(self.CREATABLES) and self._prev.text.upper()
7540
7541        # Attempt to parse the securable e.g. MySQL allows names
7542        # such as "foo.*", "*.*" which are not easily parseable yet
7543        securable = self._try_parse(self._parse_table_parts)
7544
7545        if not securable or not self._match_text_seq("TO"):
7546            return self._parse_as_command(start)
7547
7548        principals = self._parse_csv(self._parse_grant_principal)
7549
7550        grant_option = self._match_text_seq("WITH", "GRANT", "OPTION")
7551
7552        if self._curr:
7553            return self._parse_as_command(start)
7554
7555        return self.expression(
7556            exp.Grant,
7557            privileges=privileges,
7558            kind=kind,
7559            securable=securable,
7560            principals=principals,
7561            grant_option=grant_option,
7562        )
7563
7564    def _parse_overlay(self) -> exp.Overlay:
7565        return self.expression(
7566            exp.Overlay,
7567            **{  # type: ignore
7568                "this": self._parse_bitwise(),
7569                "expression": self._match_text_seq("PLACING") and self._parse_bitwise(),
7570                "from": self._match_text_seq("FROM") and self._parse_bitwise(),
7571                "for": self._match_text_seq("FOR") and self._parse_bitwise(),
7572            },
7573        )
logger = <Logger sqlglot (WARNING)>
OPTIONS_TYPE = typing.Dict[str, typing.Sequence[typing.Union[typing.Sequence[str], str]]]
def build_var_map(args: List) -> sqlglot.expressions.StarMap | sqlglot.expressions.VarMap:
26def build_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
27    if len(args) == 1 and args[0].is_star:
28        return exp.StarMap(this=args[0])
29
30    keys = []
31    values = []
32    for i in range(0, len(args), 2):
33        keys.append(args[i])
34        values.append(args[i + 1])
35
36    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:
39def build_like(args: t.List) -> exp.Escape | exp.Like:
40    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
41    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]]:
44def binary_range_parser(
45    expr_type: t.Type[exp.Expression], reverse_args: bool = False
46) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
47    def _parse_binary_range(
48        self: Parser, this: t.Optional[exp.Expression]
49    ) -> t.Optional[exp.Expression]:
50        expression = self._parse_bitwise()
51        if reverse_args:
52            this, expression = expression, this
53        return self._parse_escape(self.expression(expr_type, this=this, expression=expression))
54
55    return _parse_binary_range
def build_logarithm( args: List, dialect: sqlglot.dialects.dialect.Dialect) -> sqlglot.expressions.Func:
58def build_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
59    # Default argument order is base, expression
60    this = seq_get(args, 0)
61    expression = seq_get(args, 1)
62
63    if expression:
64        if not dialect.LOG_BASE_FIRST:
65            this, expression = expression, this
66        return exp.Log(this=this, expression=expression)
67
68    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.Dialect) -> sqlglot.expressions.Hex | sqlglot.expressions.LowerHex:
71def build_hex(args: t.List, dialect: Dialect) -> exp.Hex | exp.LowerHex:
72    arg = seq_get(args, 0)
73    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:
76def build_lower(args: t.List) -> exp.Lower | exp.Hex:
77    # LOWER(HEX(..)) can be simplified to LowerHex to simplify its transpilation
78    arg = seq_get(args, 0)
79    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:
82def build_upper(args: t.List) -> exp.Upper | exp.Hex:
83    # UPPER(HEX(..)) can be simplified to Hex to simplify its transpilation
84    arg = seq_get(args, 0)
85    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.Dialect], ~E]:
88def build_extract_json_with_path(expr_type: t.Type[E]) -> t.Callable[[t.List, Dialect], E]:
89    def _builder(args: t.List, dialect: Dialect) -> E:
90        expression = expr_type(
91            this=seq_get(args, 0), expression=dialect.to_json_path(seq_get(args, 1))
92        )
93        if len(args) > 2 and expr_type is exp.JSONExtract:
94            expression.set("expressions", args[2:])
95
96        return expression
97
98    return _builder
def build_mod(args: List) -> sqlglot.expressions.Mod:
101def build_mod(args: t.List) -> exp.Mod:
102    this = seq_get(args, 0)
103    expression = seq_get(args, 1)
104
105    # Wrap the operands if they are binary nodes, e.g. MOD(a + 1, 7) -> (a + 1) % 7
106    this = exp.Paren(this=this) if isinstance(this, exp.Binary) else this
107    expression = exp.Paren(this=expression) if isinstance(expression, exp.Binary) else expression
108
109    return exp.Mod(this=this, expression=expression)
def build_pad(args: List, is_left: bool = True):
112def build_pad(args: t.List, is_left: bool = True):
113    return exp.Pad(
114        this=seq_get(args, 0),
115        expression=seq_get(args, 1),
116        fill_pattern=seq_get(args, 2),
117        is_left=is_left,
118    )
def build_array_constructor( exp_class: Type[~E], args: List, bracket_kind: sqlglot.tokens.TokenType, dialect: sqlglot.dialects.dialect.Dialect) -> sqlglot.expressions.Expression:
121def build_array_constructor(
122    exp_class: t.Type[E], args: t.List, bracket_kind: TokenType, dialect: Dialect
123) -> exp.Expression:
124    array_exp = exp_class(expressions=args)
125
126    if exp_class == exp.Array and dialect.HAS_DISTINCT_ARRAY_CONSTRUCTORS:
127        array_exp.set("bracket_notation", bracket_kind == TokenType.L_BRACKET)
128
129    return array_exp
def build_convert_timezone( args: List, default_source_tz: Optional[str] = None) -> Union[sqlglot.expressions.ConvertTimezone, sqlglot.expressions.Anonymous]:
132def build_convert_timezone(
133    args: t.List, default_source_tz: t.Optional[str] = None
134) -> t.Union[exp.ConvertTimezone, exp.Anonymous]:
135    if len(args) == 2:
136        source_tz = exp.Literal.string(default_source_tz) if default_source_tz else None
137        return exp.ConvertTimezone(
138            source_tz=source_tz, target_tz=seq_get(args, 0), timestamp=seq_get(args, 1)
139        )
140
141    return exp.ConvertTimezone.from_arg_list(args)
def build_trim(args: List, is_left: bool = True):
144def build_trim(args: t.List, is_left: bool = True):
145    return exp.Trim(
146        this=seq_get(args, 0),
147        expression=seq_get(args, 1),
148        position="LEADING" if is_left else "TRAILING",
149    )
def build_coalesce( args: List, is_nvl: Optional[bool] = None) -> sqlglot.expressions.Coalesce:
152def build_coalesce(args: t.List, is_nvl: t.Optional[bool] = None) -> exp.Coalesce:
153    return exp.Coalesce(this=seq_get(args, 0), expressions=args[1:], is_nvl=is_nvl)
class Parser:
 166class Parser(metaclass=_Parser):
 167    """
 168    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
 169
 170    Args:
 171        error_level: The desired error level.
 172            Default: ErrorLevel.IMMEDIATE
 173        error_message_context: The amount of context to capture from a query string when displaying
 174            the error message (in number of characters).
 175            Default: 100
 176        max_errors: Maximum number of error messages to include in a raised ParseError.
 177            This is only relevant if error_level is ErrorLevel.RAISE.
 178            Default: 3
 179    """
 180
 181    FUNCTIONS: t.Dict[str, t.Callable] = {
 182        **{name: func.from_arg_list for name, func in exp.FUNCTION_BY_NAME.items()},
 183        **dict.fromkeys(("COALESCE", "IFNULL", "NVL"), build_coalesce),
 184        "ARRAY": lambda args, dialect: exp.Array(expressions=args),
 185        "ARRAYAGG": lambda args, dialect: exp.ArrayAgg(
 186            this=seq_get(args, 0), nulls_excluded=dialect.ARRAY_AGG_INCLUDES_NULLS is None or None
 187        ),
 188        "ARRAY_AGG": lambda args, dialect: exp.ArrayAgg(
 189            this=seq_get(args, 0), nulls_excluded=dialect.ARRAY_AGG_INCLUDES_NULLS is None or None
 190        ),
 191        "CHAR": lambda args: exp.Chr(expressions=args),
 192        "CHR": lambda args: exp.Chr(expressions=args),
 193        "COUNT": lambda args: exp.Count(this=seq_get(args, 0), expressions=args[1:], big_int=True),
 194        "CONCAT": lambda args, dialect: exp.Concat(
 195            expressions=args,
 196            safe=not dialect.STRICT_STRING_CONCAT,
 197            coalesce=dialect.CONCAT_COALESCE,
 198        ),
 199        "CONCAT_WS": lambda args, dialect: exp.ConcatWs(
 200            expressions=args,
 201            safe=not dialect.STRICT_STRING_CONCAT,
 202            coalesce=dialect.CONCAT_COALESCE,
 203        ),
 204        "CONVERT_TIMEZONE": build_convert_timezone,
 205        "DATE_TO_DATE_STR": lambda args: exp.Cast(
 206            this=seq_get(args, 0),
 207            to=exp.DataType(this=exp.DataType.Type.TEXT),
 208        ),
 209        "GENERATE_DATE_ARRAY": lambda args: exp.GenerateDateArray(
 210            start=seq_get(args, 0),
 211            end=seq_get(args, 1),
 212            step=seq_get(args, 2) or exp.Interval(this=exp.Literal.number(1), unit=exp.var("DAY")),
 213        ),
 214        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
 215        "HEX": build_hex,
 216        "INSTR": lambda args: exp.StrPosition(this=seq_get(args, 0), substr=seq_get(args, 1)),
 217        "JSON_EXTRACT": build_extract_json_with_path(exp.JSONExtract),
 218        "JSON_EXTRACT_SCALAR": build_extract_json_with_path(exp.JSONExtractScalar),
 219        "JSON_EXTRACT_PATH_TEXT": build_extract_json_with_path(exp.JSONExtractScalar),
 220        "LIKE": build_like,
 221        "LOG": build_logarithm,
 222        "LOG2": lambda args: exp.Log(this=exp.Literal.number(2), expression=seq_get(args, 0)),
 223        "LOG10": lambda args: exp.Log(this=exp.Literal.number(10), expression=seq_get(args, 0)),
 224        "LOWER": build_lower,
 225        "LPAD": lambda args: build_pad(args),
 226        "LEFTPAD": lambda args: build_pad(args),
 227        "LTRIM": lambda args: build_trim(args),
 228        "MOD": build_mod,
 229        "RIGHTPAD": lambda args: build_pad(args, is_left=False),
 230        "RPAD": lambda args: build_pad(args, is_left=False),
 231        "RTRIM": lambda args: build_trim(args, is_left=False),
 232        "SCOPE_RESOLUTION": lambda args: exp.ScopeResolution(expression=seq_get(args, 0))
 233        if len(args) != 2
 234        else exp.ScopeResolution(this=seq_get(args, 0), expression=seq_get(args, 1)),
 235        "TIME_TO_TIME_STR": lambda args: exp.Cast(
 236            this=seq_get(args, 0),
 237            to=exp.DataType(this=exp.DataType.Type.TEXT),
 238        ),
 239        "TO_HEX": build_hex,
 240        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
 241            this=exp.Cast(
 242                this=seq_get(args, 0),
 243                to=exp.DataType(this=exp.DataType.Type.TEXT),
 244            ),
 245            start=exp.Literal.number(1),
 246            length=exp.Literal.number(10),
 247        ),
 248        "UNNEST": lambda args: exp.Unnest(expressions=ensure_list(seq_get(args, 0))),
 249        "UPPER": build_upper,
 250        "VAR_MAP": build_var_map,
 251    }
 252
 253    NO_PAREN_FUNCTIONS = {
 254        TokenType.CURRENT_DATE: exp.CurrentDate,
 255        TokenType.CURRENT_DATETIME: exp.CurrentDate,
 256        TokenType.CURRENT_TIME: exp.CurrentTime,
 257        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
 258        TokenType.CURRENT_USER: exp.CurrentUser,
 259    }
 260
 261    STRUCT_TYPE_TOKENS = {
 262        TokenType.NESTED,
 263        TokenType.OBJECT,
 264        TokenType.STRUCT,
 265        TokenType.UNION,
 266    }
 267
 268    NESTED_TYPE_TOKENS = {
 269        TokenType.ARRAY,
 270        TokenType.LIST,
 271        TokenType.LOWCARDINALITY,
 272        TokenType.MAP,
 273        TokenType.NULLABLE,
 274        TokenType.RANGE,
 275        *STRUCT_TYPE_TOKENS,
 276    }
 277
 278    ENUM_TYPE_TOKENS = {
 279        TokenType.ENUM,
 280        TokenType.ENUM8,
 281        TokenType.ENUM16,
 282    }
 283
 284    AGGREGATE_TYPE_TOKENS = {
 285        TokenType.AGGREGATEFUNCTION,
 286        TokenType.SIMPLEAGGREGATEFUNCTION,
 287    }
 288
 289    TYPE_TOKENS = {
 290        TokenType.BIT,
 291        TokenType.BOOLEAN,
 292        TokenType.TINYINT,
 293        TokenType.UTINYINT,
 294        TokenType.SMALLINT,
 295        TokenType.USMALLINT,
 296        TokenType.INT,
 297        TokenType.UINT,
 298        TokenType.BIGINT,
 299        TokenType.UBIGINT,
 300        TokenType.INT128,
 301        TokenType.UINT128,
 302        TokenType.INT256,
 303        TokenType.UINT256,
 304        TokenType.MEDIUMINT,
 305        TokenType.UMEDIUMINT,
 306        TokenType.FIXEDSTRING,
 307        TokenType.FLOAT,
 308        TokenType.DOUBLE,
 309        TokenType.CHAR,
 310        TokenType.NCHAR,
 311        TokenType.VARCHAR,
 312        TokenType.NVARCHAR,
 313        TokenType.BPCHAR,
 314        TokenType.TEXT,
 315        TokenType.MEDIUMTEXT,
 316        TokenType.LONGTEXT,
 317        TokenType.MEDIUMBLOB,
 318        TokenType.LONGBLOB,
 319        TokenType.BINARY,
 320        TokenType.VARBINARY,
 321        TokenType.JSON,
 322        TokenType.JSONB,
 323        TokenType.INTERVAL,
 324        TokenType.TINYBLOB,
 325        TokenType.TINYTEXT,
 326        TokenType.TIME,
 327        TokenType.TIMETZ,
 328        TokenType.TIMESTAMP,
 329        TokenType.TIMESTAMP_S,
 330        TokenType.TIMESTAMP_MS,
 331        TokenType.TIMESTAMP_NS,
 332        TokenType.TIMESTAMPTZ,
 333        TokenType.TIMESTAMPLTZ,
 334        TokenType.TIMESTAMPNTZ,
 335        TokenType.DATETIME,
 336        TokenType.DATETIME64,
 337        TokenType.DATE,
 338        TokenType.DATE32,
 339        TokenType.INT4RANGE,
 340        TokenType.INT4MULTIRANGE,
 341        TokenType.INT8RANGE,
 342        TokenType.INT8MULTIRANGE,
 343        TokenType.NUMRANGE,
 344        TokenType.NUMMULTIRANGE,
 345        TokenType.TSRANGE,
 346        TokenType.TSMULTIRANGE,
 347        TokenType.TSTZRANGE,
 348        TokenType.TSTZMULTIRANGE,
 349        TokenType.DATERANGE,
 350        TokenType.DATEMULTIRANGE,
 351        TokenType.DECIMAL,
 352        TokenType.DECIMAL32,
 353        TokenType.DECIMAL64,
 354        TokenType.DECIMAL128,
 355        TokenType.DECIMAL256,
 356        TokenType.UDECIMAL,
 357        TokenType.BIGDECIMAL,
 358        TokenType.UUID,
 359        TokenType.GEOGRAPHY,
 360        TokenType.GEOMETRY,
 361        TokenType.POINT,
 362        TokenType.RING,
 363        TokenType.LINESTRING,
 364        TokenType.MULTILINESTRING,
 365        TokenType.POLYGON,
 366        TokenType.MULTIPOLYGON,
 367        TokenType.HLLSKETCH,
 368        TokenType.HSTORE,
 369        TokenType.PSEUDO_TYPE,
 370        TokenType.SUPER,
 371        TokenType.SERIAL,
 372        TokenType.SMALLSERIAL,
 373        TokenType.BIGSERIAL,
 374        TokenType.XML,
 375        TokenType.YEAR,
 376        TokenType.UNIQUEIDENTIFIER,
 377        TokenType.USERDEFINED,
 378        TokenType.MONEY,
 379        TokenType.SMALLMONEY,
 380        TokenType.ROWVERSION,
 381        TokenType.IMAGE,
 382        TokenType.VARIANT,
 383        TokenType.VECTOR,
 384        TokenType.OBJECT,
 385        TokenType.OBJECT_IDENTIFIER,
 386        TokenType.INET,
 387        TokenType.IPADDRESS,
 388        TokenType.IPPREFIX,
 389        TokenType.IPV4,
 390        TokenType.IPV6,
 391        TokenType.UNKNOWN,
 392        TokenType.NULL,
 393        TokenType.NAME,
 394        TokenType.TDIGEST,
 395        *ENUM_TYPE_TOKENS,
 396        *NESTED_TYPE_TOKENS,
 397        *AGGREGATE_TYPE_TOKENS,
 398    }
 399
 400    SIGNED_TO_UNSIGNED_TYPE_TOKEN = {
 401        TokenType.BIGINT: TokenType.UBIGINT,
 402        TokenType.INT: TokenType.UINT,
 403        TokenType.MEDIUMINT: TokenType.UMEDIUMINT,
 404        TokenType.SMALLINT: TokenType.USMALLINT,
 405        TokenType.TINYINT: TokenType.UTINYINT,
 406        TokenType.DECIMAL: TokenType.UDECIMAL,
 407    }
 408
 409    SUBQUERY_PREDICATES = {
 410        TokenType.ANY: exp.Any,
 411        TokenType.ALL: exp.All,
 412        TokenType.EXISTS: exp.Exists,
 413        TokenType.SOME: exp.Any,
 414    }
 415
 416    RESERVED_TOKENS = {
 417        *Tokenizer.SINGLE_TOKENS.values(),
 418        TokenType.SELECT,
 419    } - {TokenType.IDENTIFIER}
 420
 421    DB_CREATABLES = {
 422        TokenType.DATABASE,
 423        TokenType.DICTIONARY,
 424        TokenType.MODEL,
 425        TokenType.SCHEMA,
 426        TokenType.SEQUENCE,
 427        TokenType.STORAGE_INTEGRATION,
 428        TokenType.TABLE,
 429        TokenType.TAG,
 430        TokenType.VIEW,
 431        TokenType.WAREHOUSE,
 432        TokenType.STREAMLIT,
 433    }
 434
 435    CREATABLES = {
 436        TokenType.COLUMN,
 437        TokenType.CONSTRAINT,
 438        TokenType.FOREIGN_KEY,
 439        TokenType.FUNCTION,
 440        TokenType.INDEX,
 441        TokenType.PROCEDURE,
 442        *DB_CREATABLES,
 443    }
 444
 445    ALTERABLES = {
 446        TokenType.INDEX,
 447        TokenType.TABLE,
 448        TokenType.VIEW,
 449    }
 450
 451    # Tokens that can represent identifiers
 452    ID_VAR_TOKENS = {
 453        TokenType.ALL,
 454        TokenType.VAR,
 455        TokenType.ANTI,
 456        TokenType.APPLY,
 457        TokenType.ASC,
 458        TokenType.ASOF,
 459        TokenType.AUTO_INCREMENT,
 460        TokenType.BEGIN,
 461        TokenType.BPCHAR,
 462        TokenType.CACHE,
 463        TokenType.CASE,
 464        TokenType.COLLATE,
 465        TokenType.COMMAND,
 466        TokenType.COMMENT,
 467        TokenType.COMMIT,
 468        TokenType.CONSTRAINT,
 469        TokenType.COPY,
 470        TokenType.CUBE,
 471        TokenType.DEFAULT,
 472        TokenType.DELETE,
 473        TokenType.DESC,
 474        TokenType.DESCRIBE,
 475        TokenType.DICTIONARY,
 476        TokenType.DIV,
 477        TokenType.END,
 478        TokenType.EXECUTE,
 479        TokenType.ESCAPE,
 480        TokenType.FALSE,
 481        TokenType.FIRST,
 482        TokenType.FILTER,
 483        TokenType.FINAL,
 484        TokenType.FORMAT,
 485        TokenType.FULL,
 486        TokenType.IDENTIFIER,
 487        TokenType.IS,
 488        TokenType.ISNULL,
 489        TokenType.INTERVAL,
 490        TokenType.KEEP,
 491        TokenType.KILL,
 492        TokenType.LEFT,
 493        TokenType.LOAD,
 494        TokenType.MERGE,
 495        TokenType.NATURAL,
 496        TokenType.NEXT,
 497        TokenType.OFFSET,
 498        TokenType.OPERATOR,
 499        TokenType.ORDINALITY,
 500        TokenType.OVERLAPS,
 501        TokenType.OVERWRITE,
 502        TokenType.PARTITION,
 503        TokenType.PERCENT,
 504        TokenType.PIVOT,
 505        TokenType.PRAGMA,
 506        TokenType.RANGE,
 507        TokenType.RECURSIVE,
 508        TokenType.REFERENCES,
 509        TokenType.REFRESH,
 510        TokenType.RENAME,
 511        TokenType.REPLACE,
 512        TokenType.RIGHT,
 513        TokenType.ROLLUP,
 514        TokenType.ROW,
 515        TokenType.ROWS,
 516        TokenType.SEMI,
 517        TokenType.SET,
 518        TokenType.SETTINGS,
 519        TokenType.SHOW,
 520        TokenType.TEMPORARY,
 521        TokenType.TOP,
 522        TokenType.TRUE,
 523        TokenType.TRUNCATE,
 524        TokenType.UNIQUE,
 525        TokenType.UNNEST,
 526        TokenType.UNPIVOT,
 527        TokenType.UPDATE,
 528        TokenType.USE,
 529        TokenType.VOLATILE,
 530        TokenType.WINDOW,
 531        *CREATABLES,
 532        *SUBQUERY_PREDICATES,
 533        *TYPE_TOKENS,
 534        *NO_PAREN_FUNCTIONS,
 535    }
 536    ID_VAR_TOKENS.remove(TokenType.UNION)
 537
 538    INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
 539
 540    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
 541        TokenType.ANTI,
 542        TokenType.APPLY,
 543        TokenType.ASOF,
 544        TokenType.FULL,
 545        TokenType.LEFT,
 546        TokenType.LOCK,
 547        TokenType.NATURAL,
 548        TokenType.OFFSET,
 549        TokenType.RIGHT,
 550        TokenType.SEMI,
 551        TokenType.WINDOW,
 552    }
 553
 554    ALIAS_TOKENS = ID_VAR_TOKENS
 555
 556    ARRAY_CONSTRUCTORS = {
 557        "ARRAY": exp.Array,
 558        "LIST": exp.List,
 559    }
 560
 561    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
 562
 563    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
 564
 565    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
 566
 567    FUNC_TOKENS = {
 568        TokenType.COLLATE,
 569        TokenType.COMMAND,
 570        TokenType.CURRENT_DATE,
 571        TokenType.CURRENT_DATETIME,
 572        TokenType.CURRENT_TIMESTAMP,
 573        TokenType.CURRENT_TIME,
 574        TokenType.CURRENT_USER,
 575        TokenType.FILTER,
 576        TokenType.FIRST,
 577        TokenType.FORMAT,
 578        TokenType.GLOB,
 579        TokenType.IDENTIFIER,
 580        TokenType.INDEX,
 581        TokenType.ISNULL,
 582        TokenType.ILIKE,
 583        TokenType.INSERT,
 584        TokenType.LIKE,
 585        TokenType.MERGE,
 586        TokenType.OFFSET,
 587        TokenType.PRIMARY_KEY,
 588        TokenType.RANGE,
 589        TokenType.REPLACE,
 590        TokenType.RLIKE,
 591        TokenType.ROW,
 592        TokenType.UNNEST,
 593        TokenType.VAR,
 594        TokenType.LEFT,
 595        TokenType.RIGHT,
 596        TokenType.SEQUENCE,
 597        TokenType.DATE,
 598        TokenType.DATETIME,
 599        TokenType.TABLE,
 600        TokenType.TIMESTAMP,
 601        TokenType.TIMESTAMPTZ,
 602        TokenType.TRUNCATE,
 603        TokenType.WINDOW,
 604        TokenType.XOR,
 605        *TYPE_TOKENS,
 606        *SUBQUERY_PREDICATES,
 607    }
 608
 609    CONJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
 610        TokenType.AND: exp.And,
 611    }
 612
 613    ASSIGNMENT: t.Dict[TokenType, t.Type[exp.Expression]] = {
 614        TokenType.COLON_EQ: exp.PropertyEQ,
 615    }
 616
 617    DISJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
 618        TokenType.OR: exp.Or,
 619    }
 620
 621    EQUALITY = {
 622        TokenType.EQ: exp.EQ,
 623        TokenType.NEQ: exp.NEQ,
 624        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
 625    }
 626
 627    COMPARISON = {
 628        TokenType.GT: exp.GT,
 629        TokenType.GTE: exp.GTE,
 630        TokenType.LT: exp.LT,
 631        TokenType.LTE: exp.LTE,
 632    }
 633
 634    BITWISE = {
 635        TokenType.AMP: exp.BitwiseAnd,
 636        TokenType.CARET: exp.BitwiseXor,
 637        TokenType.PIPE: exp.BitwiseOr,
 638    }
 639
 640    TERM = {
 641        TokenType.DASH: exp.Sub,
 642        TokenType.PLUS: exp.Add,
 643        TokenType.MOD: exp.Mod,
 644        TokenType.COLLATE: exp.Collate,
 645    }
 646
 647    FACTOR = {
 648        TokenType.DIV: exp.IntDiv,
 649        TokenType.LR_ARROW: exp.Distance,
 650        TokenType.SLASH: exp.Div,
 651        TokenType.STAR: exp.Mul,
 652    }
 653
 654    EXPONENT: t.Dict[TokenType, t.Type[exp.Expression]] = {}
 655
 656    TIMES = {
 657        TokenType.TIME,
 658        TokenType.TIMETZ,
 659    }
 660
 661    TIMESTAMPS = {
 662        TokenType.TIMESTAMP,
 663        TokenType.TIMESTAMPTZ,
 664        TokenType.TIMESTAMPLTZ,
 665        *TIMES,
 666    }
 667
 668    SET_OPERATIONS = {
 669        TokenType.UNION,
 670        TokenType.INTERSECT,
 671        TokenType.EXCEPT,
 672    }
 673
 674    JOIN_METHODS = {
 675        TokenType.ASOF,
 676        TokenType.NATURAL,
 677        TokenType.POSITIONAL,
 678    }
 679
 680    JOIN_SIDES = {
 681        TokenType.LEFT,
 682        TokenType.RIGHT,
 683        TokenType.FULL,
 684    }
 685
 686    JOIN_KINDS = {
 687        TokenType.ANTI,
 688        TokenType.CROSS,
 689        TokenType.INNER,
 690        TokenType.OUTER,
 691        TokenType.SEMI,
 692        TokenType.STRAIGHT_JOIN,
 693    }
 694
 695    JOIN_HINTS: t.Set[str] = set()
 696
 697    LAMBDAS = {
 698        TokenType.ARROW: lambda self, expressions: self.expression(
 699            exp.Lambda,
 700            this=self._replace_lambda(
 701                self._parse_assignment(),
 702                expressions,
 703            ),
 704            expressions=expressions,
 705        ),
 706        TokenType.FARROW: lambda self, expressions: self.expression(
 707            exp.Kwarg,
 708            this=exp.var(expressions[0].name),
 709            expression=self._parse_assignment(),
 710        ),
 711    }
 712
 713    COLUMN_OPERATORS = {
 714        TokenType.DOT: None,
 715        TokenType.DCOLON: lambda self, this, to: self.expression(
 716            exp.Cast if self.STRICT_CAST else exp.TryCast,
 717            this=this,
 718            to=to,
 719        ),
 720        TokenType.ARROW: lambda self, this, path: self.expression(
 721            exp.JSONExtract,
 722            this=this,
 723            expression=self.dialect.to_json_path(path),
 724            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
 725        ),
 726        TokenType.DARROW: lambda self, this, path: self.expression(
 727            exp.JSONExtractScalar,
 728            this=this,
 729            expression=self.dialect.to_json_path(path),
 730            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
 731        ),
 732        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
 733            exp.JSONBExtract,
 734            this=this,
 735            expression=path,
 736        ),
 737        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
 738            exp.JSONBExtractScalar,
 739            this=this,
 740            expression=path,
 741        ),
 742        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
 743            exp.JSONBContains,
 744            this=this,
 745            expression=key,
 746        ),
 747    }
 748
 749    EXPRESSION_PARSERS = {
 750        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
 751        exp.Column: lambda self: self._parse_column(),
 752        exp.Condition: lambda self: self._parse_assignment(),
 753        exp.DataType: lambda self: self._parse_types(allow_identifiers=False, schema=True),
 754        exp.Expression: lambda self: self._parse_expression(),
 755        exp.From: lambda self: self._parse_from(joins=True),
 756        exp.Group: lambda self: self._parse_group(),
 757        exp.Having: lambda self: self._parse_having(),
 758        exp.Identifier: lambda self: self._parse_id_var(),
 759        exp.Join: lambda self: self._parse_join(),
 760        exp.Lambda: lambda self: self._parse_lambda(),
 761        exp.Lateral: lambda self: self._parse_lateral(),
 762        exp.Limit: lambda self: self._parse_limit(),
 763        exp.Offset: lambda self: self._parse_offset(),
 764        exp.Order: lambda self: self._parse_order(),
 765        exp.Ordered: lambda self: self._parse_ordered(),
 766        exp.Properties: lambda self: self._parse_properties(),
 767        exp.Qualify: lambda self: self._parse_qualify(),
 768        exp.Returning: lambda self: self._parse_returning(),
 769        exp.Select: lambda self: self._parse_select(),
 770        exp.Sort: lambda self: self._parse_sort(exp.Sort, TokenType.SORT_BY),
 771        exp.Table: lambda self: self._parse_table_parts(),
 772        exp.TableAlias: lambda self: self._parse_table_alias(),
 773        exp.When: lambda self: seq_get(self._parse_when_matched(), 0),
 774        exp.Where: lambda self: self._parse_where(),
 775        exp.Window: lambda self: self._parse_named_window(),
 776        exp.With: lambda self: self._parse_with(),
 777        "JOIN_TYPE": lambda self: self._parse_join_parts(),
 778    }
 779
 780    STATEMENT_PARSERS = {
 781        TokenType.ALTER: lambda self: self._parse_alter(),
 782        TokenType.BEGIN: lambda self: self._parse_transaction(),
 783        TokenType.CACHE: lambda self: self._parse_cache(),
 784        TokenType.COMMENT: lambda self: self._parse_comment(),
 785        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
 786        TokenType.COPY: lambda self: self._parse_copy(),
 787        TokenType.CREATE: lambda self: self._parse_create(),
 788        TokenType.DELETE: lambda self: self._parse_delete(),
 789        TokenType.DESC: lambda self: self._parse_describe(),
 790        TokenType.DESCRIBE: lambda self: self._parse_describe(),
 791        TokenType.DROP: lambda self: self._parse_drop(),
 792        TokenType.GRANT: lambda self: self._parse_grant(),
 793        TokenType.INSERT: lambda self: self._parse_insert(),
 794        TokenType.KILL: lambda self: self._parse_kill(),
 795        TokenType.LOAD: lambda self: self._parse_load(),
 796        TokenType.MERGE: lambda self: self._parse_merge(),
 797        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
 798        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
 799        TokenType.REFRESH: lambda self: self._parse_refresh(),
 800        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
 801        TokenType.SET: lambda self: self._parse_set(),
 802        TokenType.TRUNCATE: lambda self: self._parse_truncate_table(),
 803        TokenType.UNCACHE: lambda self: self._parse_uncache(),
 804        TokenType.UPDATE: lambda self: self._parse_update(),
 805        TokenType.USE: lambda self: self.expression(
 806            exp.Use,
 807            kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
 808            this=self._parse_table(schema=False),
 809        ),
 810        TokenType.SEMICOLON: lambda self: self.expression(exp.Semicolon),
 811    }
 812
 813    UNARY_PARSERS = {
 814        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
 815        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
 816        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
 817        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
 818        TokenType.PIPE_SLASH: lambda self: self.expression(exp.Sqrt, this=self._parse_unary()),
 819        TokenType.DPIPE_SLASH: lambda self: self.expression(exp.Cbrt, this=self._parse_unary()),
 820    }
 821
 822    STRING_PARSERS = {
 823        TokenType.HEREDOC_STRING: lambda self, token: self.expression(
 824            exp.RawString, this=token.text
 825        ),
 826        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
 827            exp.National, this=token.text
 828        ),
 829        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
 830        TokenType.STRING: lambda self, token: self.expression(
 831            exp.Literal, this=token.text, is_string=True
 832        ),
 833        TokenType.UNICODE_STRING: lambda self, token: self.expression(
 834            exp.UnicodeString,
 835            this=token.text,
 836            escape=self._match_text_seq("UESCAPE") and self._parse_string(),
 837        ),
 838    }
 839
 840    NUMERIC_PARSERS = {
 841        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
 842        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
 843        TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text),
 844        TokenType.NUMBER: lambda self, token: self.expression(
 845            exp.Literal, this=token.text, is_string=False
 846        ),
 847    }
 848
 849    PRIMARY_PARSERS = {
 850        **STRING_PARSERS,
 851        **NUMERIC_PARSERS,
 852        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
 853        TokenType.NULL: lambda self, _: self.expression(exp.Null),
 854        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
 855        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
 856        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
 857        TokenType.STAR: lambda self, _: self._parse_star_ops(),
 858    }
 859
 860    PLACEHOLDER_PARSERS = {
 861        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
 862        TokenType.PARAMETER: lambda self: self._parse_parameter(),
 863        TokenType.COLON: lambda self: (
 864            self.expression(exp.Placeholder, this=self._prev.text)
 865            if self._match_set(self.ID_VAR_TOKENS)
 866            else None
 867        ),
 868    }
 869
 870    RANGE_PARSERS = {
 871        TokenType.AT_GT: binary_range_parser(exp.ArrayContainsAll),
 872        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
 873        TokenType.GLOB: binary_range_parser(exp.Glob),
 874        TokenType.ILIKE: binary_range_parser(exp.ILike),
 875        TokenType.IN: lambda self, this: self._parse_in(this),
 876        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
 877        TokenType.IS: lambda self, this: self._parse_is(this),
 878        TokenType.LIKE: binary_range_parser(exp.Like),
 879        TokenType.LT_AT: binary_range_parser(exp.ArrayContainsAll, reverse_args=True),
 880        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
 881        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
 882        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
 883        TokenType.FOR: lambda self, this: self._parse_comprehension(this),
 884    }
 885
 886    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
 887        "ALLOWED_VALUES": lambda self: self.expression(
 888            exp.AllowedValuesProperty, expressions=self._parse_csv(self._parse_primary)
 889        ),
 890        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
 891        "AUTO": lambda self: self._parse_auto_property(),
 892        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
 893        "BACKUP": lambda self: self.expression(
 894            exp.BackupProperty, this=self._parse_var(any_token=True)
 895        ),
 896        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
 897        "CHARSET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 898        "CHARACTER SET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 899        "CHECKSUM": lambda self: self._parse_checksum(),
 900        "CLUSTER BY": lambda self: self._parse_cluster(),
 901        "CLUSTERED": lambda self: self._parse_clustered_by(),
 902        "COLLATE": lambda self, **kwargs: self._parse_property_assignment(
 903            exp.CollateProperty, **kwargs
 904        ),
 905        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
 906        "CONTAINS": lambda self: self._parse_contains_property(),
 907        "COPY": lambda self: self._parse_copy_property(),
 908        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
 909        "DATA_DELETION": lambda self: self._parse_data_deletion_property(),
 910        "DEFINER": lambda self: self._parse_definer(),
 911        "DETERMINISTIC": lambda self: self.expression(
 912            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 913        ),
 914        "DISTRIBUTED": lambda self: self._parse_distributed_property(),
 915        "DUPLICATE": lambda self: self._parse_duplicate(),
 916        "DYNAMIC": lambda self: self.expression(exp.DynamicProperty),
 917        "DISTKEY": lambda self: self._parse_distkey(),
 918        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
 919        "EMPTY": lambda self: self.expression(exp.EmptyProperty),
 920        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
 921        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
 922        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
 923        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
 924        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 925        "FREESPACE": lambda self: self._parse_freespace(),
 926        "GLOBAL": lambda self: self.expression(exp.GlobalProperty),
 927        "HEAP": lambda self: self.expression(exp.HeapProperty),
 928        "ICEBERG": lambda self: self.expression(exp.IcebergProperty),
 929        "IMMUTABLE": lambda self: self.expression(
 930            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 931        ),
 932        "INHERITS": lambda self: self.expression(
 933            exp.InheritsProperty, expressions=self._parse_wrapped_csv(self._parse_table)
 934        ),
 935        "INPUT": lambda self: self.expression(exp.InputModelProperty, this=self._parse_schema()),
 936        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
 937        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
 938        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
 939        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
 940        "LIKE": lambda self: self._parse_create_like(),
 941        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
 942        "LOCK": lambda self: self._parse_locking(),
 943        "LOCKING": lambda self: self._parse_locking(),
 944        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
 945        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
 946        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
 947        "MODIFIES": lambda self: self._parse_modifies_property(),
 948        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
 949        "NO": lambda self: self._parse_no_property(),
 950        "ON": lambda self: self._parse_on_property(),
 951        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
 952        "OUTPUT": lambda self: self.expression(exp.OutputModelProperty, this=self._parse_schema()),
 953        "PARTITION": lambda self: self._parse_partitioned_of(),
 954        "PARTITION BY": lambda self: self._parse_partitioned_by(),
 955        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
 956        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
 957        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
 958        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
 959        "READS": lambda self: self._parse_reads_property(),
 960        "REMOTE": lambda self: self._parse_remote_with_connection(),
 961        "RETURNS": lambda self: self._parse_returns(),
 962        "STRICT": lambda self: self.expression(exp.StrictProperty),
 963        "STREAMING": lambda self: self.expression(exp.StreamingTableProperty),
 964        "ROW": lambda self: self._parse_row(),
 965        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
 966        "SAMPLE": lambda self: self.expression(
 967            exp.SampleProperty, this=self._match_text_seq("BY") and self._parse_bitwise()
 968        ),
 969        "SECURE": lambda self: self.expression(exp.SecureProperty),
 970        "SECURITY": lambda self: self._parse_security(),
 971        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
 972        "SETTINGS": lambda self: self._parse_settings_property(),
 973        "SHARING": lambda self: self._parse_property_assignment(exp.SharingProperty),
 974        "SORTKEY": lambda self: self._parse_sortkey(),
 975        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
 976        "STABLE": lambda self: self.expression(
 977            exp.StabilityProperty, this=exp.Literal.string("STABLE")
 978        ),
 979        "STORED": lambda self: self._parse_stored(),
 980        "SYSTEM_VERSIONING": lambda self: self._parse_system_versioning_property(),
 981        "TBLPROPERTIES": lambda self: self._parse_wrapped_properties(),
 982        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
 983        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
 984        "TO": lambda self: self._parse_to_table(),
 985        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
 986        "TRANSFORM": lambda self: self.expression(
 987            exp.TransformModelProperty, expressions=self._parse_wrapped_csv(self._parse_expression)
 988        ),
 989        "TTL": lambda self: self._parse_ttl(),
 990        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 991        "UNLOGGED": lambda self: self.expression(exp.UnloggedProperty),
 992        "VOLATILE": lambda self: self._parse_volatile_property(),
 993        "WITH": lambda self: self._parse_with_property(),
 994    }
 995
 996    CONSTRAINT_PARSERS = {
 997        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
 998        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
 999        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
1000        "CHARACTER SET": lambda self: self.expression(
1001            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
1002        ),
1003        "CHECK": lambda self: self.expression(
1004            exp.CheckColumnConstraint,
1005            this=self._parse_wrapped(self._parse_assignment),
1006            enforced=self._match_text_seq("ENFORCED"),
1007        ),
1008        "COLLATE": lambda self: self.expression(
1009            exp.CollateColumnConstraint,
1010            this=self._parse_identifier() or self._parse_column(),
1011        ),
1012        "COMMENT": lambda self: self.expression(
1013            exp.CommentColumnConstraint, this=self._parse_string()
1014        ),
1015        "COMPRESS": lambda self: self._parse_compress(),
1016        "CLUSTERED": lambda self: self.expression(
1017            exp.ClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
1018        ),
1019        "NONCLUSTERED": lambda self: self.expression(
1020            exp.NonClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
1021        ),
1022        "DEFAULT": lambda self: self.expression(
1023            exp.DefaultColumnConstraint, this=self._parse_bitwise()
1024        ),
1025        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
1026        "EPHEMERAL": lambda self: self.expression(
1027            exp.EphemeralColumnConstraint, this=self._parse_bitwise()
1028        ),
1029        "EXCLUDE": lambda self: self.expression(
1030            exp.ExcludeColumnConstraint, this=self._parse_index_params()
1031        ),
1032        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
1033        "FORMAT": lambda self: self.expression(
1034            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
1035        ),
1036        "GENERATED": lambda self: self._parse_generated_as_identity(),
1037        "IDENTITY": lambda self: self._parse_auto_increment(),
1038        "INLINE": lambda self: self._parse_inline(),
1039        "LIKE": lambda self: self._parse_create_like(),
1040        "NOT": lambda self: self._parse_not_constraint(),
1041        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
1042        "ON": lambda self: (
1043            self._match(TokenType.UPDATE)
1044            and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function())
1045        )
1046        or self.expression(exp.OnProperty, this=self._parse_id_var()),
1047        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
1048        "PERIOD": lambda self: self._parse_period_for_system_time(),
1049        "PRIMARY KEY": lambda self: self._parse_primary_key(),
1050        "REFERENCES": lambda self: self._parse_references(match=False),
1051        "TITLE": lambda self: self.expression(
1052            exp.TitleColumnConstraint, this=self._parse_var_or_string()
1053        ),
1054        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
1055        "UNIQUE": lambda self: self._parse_unique(),
1056        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
1057        "WITH": lambda self: self.expression(
1058            exp.Properties, expressions=self._parse_wrapped_properties()
1059        ),
1060    }
1061
1062    ALTER_PARSERS = {
1063        "ADD": lambda self: self._parse_alter_table_add(),
1064        "AS": lambda self: self._parse_select(),
1065        "ALTER": lambda self: self._parse_alter_table_alter(),
1066        "CLUSTER BY": lambda self: self._parse_cluster(wrapped=True),
1067        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
1068        "DROP": lambda self: self._parse_alter_table_drop(),
1069        "RENAME": lambda self: self._parse_alter_table_rename(),
1070        "SET": lambda self: self._parse_alter_table_set(),
1071        "SWAP": lambda self: self.expression(
1072            exp.SwapTable, this=self._match(TokenType.WITH) and self._parse_table(schema=True)
1073        ),
1074    }
1075
1076    ALTER_ALTER_PARSERS = {
1077        "DISTKEY": lambda self: self._parse_alter_diststyle(),
1078        "DISTSTYLE": lambda self: self._parse_alter_diststyle(),
1079        "SORTKEY": lambda self: self._parse_alter_sortkey(),
1080        "COMPOUND": lambda self: self._parse_alter_sortkey(compound=True),
1081    }
1082
1083    SCHEMA_UNNAMED_CONSTRAINTS = {
1084        "CHECK",
1085        "EXCLUDE",
1086        "FOREIGN KEY",
1087        "LIKE",
1088        "PERIOD",
1089        "PRIMARY KEY",
1090        "UNIQUE",
1091    }
1092
1093    NO_PAREN_FUNCTION_PARSERS = {
1094        "ANY": lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
1095        "CASE": lambda self: self._parse_case(),
1096        "CONNECT_BY_ROOT": lambda self: self.expression(
1097            exp.ConnectByRoot, this=self._parse_column()
1098        ),
1099        "IF": lambda self: self._parse_if(),
1100        "NEXT": lambda self: self._parse_next_value_for(),
1101    }
1102
1103    INVALID_FUNC_NAME_TOKENS = {
1104        TokenType.IDENTIFIER,
1105        TokenType.STRING,
1106    }
1107
1108    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
1109
1110    KEY_VALUE_DEFINITIONS = (exp.Alias, exp.EQ, exp.PropertyEQ, exp.Slice)
1111
1112    FUNCTION_PARSERS = {
1113        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
1114        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
1115        "DECODE": lambda self: self._parse_decode(),
1116        "EXTRACT": lambda self: self._parse_extract(),
1117        "GAP_FILL": lambda self: self._parse_gap_fill(),
1118        "JSON_OBJECT": lambda self: self._parse_json_object(),
1119        "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
1120        "JSON_TABLE": lambda self: self._parse_json_table(),
1121        "MATCH": lambda self: self._parse_match_against(),
1122        "NORMALIZE": lambda self: self._parse_normalize(),
1123        "OPENJSON": lambda self: self._parse_open_json(),
1124        "OVERLAY": lambda self: self._parse_overlay(),
1125        "POSITION": lambda self: self._parse_position(),
1126        "PREDICT": lambda self: self._parse_predict(),
1127        "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
1128        "STRING_AGG": lambda self: self._parse_string_agg(),
1129        "SUBSTRING": lambda self: self._parse_substring(),
1130        "TRIM": lambda self: self._parse_trim(),
1131        "TRY_CAST": lambda self: self._parse_cast(False, safe=True),
1132        "TRY_CONVERT": lambda self: self._parse_convert(False, safe=True),
1133    }
1134
1135    QUERY_MODIFIER_PARSERS = {
1136        TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
1137        TokenType.PREWHERE: lambda self: ("prewhere", self._parse_prewhere()),
1138        TokenType.WHERE: lambda self: ("where", self._parse_where()),
1139        TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
1140        TokenType.HAVING: lambda self: ("having", self._parse_having()),
1141        TokenType.QUALIFY: lambda self: ("qualify", self._parse_qualify()),
1142        TokenType.WINDOW: lambda self: ("windows", self._parse_window_clause()),
1143        TokenType.ORDER_BY: lambda self: ("order", self._parse_order()),
1144        TokenType.LIMIT: lambda self: ("limit", self._parse_limit()),
1145        TokenType.FETCH: lambda self: ("limit", self._parse_limit()),
1146        TokenType.OFFSET: lambda self: ("offset", self._parse_offset()),
1147        TokenType.FOR: lambda self: ("locks", self._parse_locks()),
1148        TokenType.LOCK: lambda self: ("locks", self._parse_locks()),
1149        TokenType.TABLE_SAMPLE: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
1150        TokenType.USING: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
1151        TokenType.CLUSTER_BY: lambda self: (
1152            "cluster",
1153            self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
1154        ),
1155        TokenType.DISTRIBUTE_BY: lambda self: (
1156            "distribute",
1157            self._parse_sort(exp.Distribute, TokenType.DISTRIBUTE_BY),
1158        ),
1159        TokenType.SORT_BY: lambda self: ("sort", self._parse_sort(exp.Sort, TokenType.SORT_BY)),
1160        TokenType.CONNECT_BY: lambda self: ("connect", self._parse_connect(skip_start_token=True)),
1161        TokenType.START_WITH: lambda self: ("connect", self._parse_connect()),
1162    }
1163
1164    SET_PARSERS = {
1165        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
1166        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
1167        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
1168        "TRANSACTION": lambda self: self._parse_set_transaction(),
1169    }
1170
1171    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
1172
1173    TYPE_LITERAL_PARSERS = {
1174        exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
1175    }
1176
1177    TYPE_CONVERTERS: t.Dict[exp.DataType.Type, t.Callable[[exp.DataType], exp.DataType]] = {}
1178
1179    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
1180
1181    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
1182
1183    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
1184    TRANSACTION_CHARACTERISTICS: OPTIONS_TYPE = {
1185        "ISOLATION": (
1186            ("LEVEL", "REPEATABLE", "READ"),
1187            ("LEVEL", "READ", "COMMITTED"),
1188            ("LEVEL", "READ", "UNCOMITTED"),
1189            ("LEVEL", "SERIALIZABLE"),
1190        ),
1191        "READ": ("WRITE", "ONLY"),
1192    }
1193
1194    CONFLICT_ACTIONS: OPTIONS_TYPE = dict.fromkeys(
1195        ("ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK", "UPDATE"), tuple()
1196    )
1197    CONFLICT_ACTIONS["DO"] = ("NOTHING", "UPDATE")
1198
1199    CREATE_SEQUENCE: OPTIONS_TYPE = {
1200        "SCALE": ("EXTEND", "NOEXTEND"),
1201        "SHARD": ("EXTEND", "NOEXTEND"),
1202        "NO": ("CYCLE", "CACHE", "MAXVALUE", "MINVALUE"),
1203        **dict.fromkeys(
1204            (
1205                "SESSION",
1206                "GLOBAL",
1207                "KEEP",
1208                "NOKEEP",
1209                "ORDER",
1210                "NOORDER",
1211                "NOCACHE",
1212                "CYCLE",
1213                "NOCYCLE",
1214                "NOMINVALUE",
1215                "NOMAXVALUE",
1216                "NOSCALE",
1217                "NOSHARD",
1218            ),
1219            tuple(),
1220        ),
1221    }
1222
1223    ISOLATED_LOADING_OPTIONS: OPTIONS_TYPE = {"FOR": ("ALL", "INSERT", "NONE")}
1224
1225    USABLES: OPTIONS_TYPE = dict.fromkeys(
1226        ("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA", "CATALOG"), tuple()
1227    )
1228
1229    CAST_ACTIONS: OPTIONS_TYPE = dict.fromkeys(("RENAME", "ADD"), ("FIELDS",))
1230
1231    SCHEMA_BINDING_OPTIONS: OPTIONS_TYPE = {
1232        "TYPE": ("EVOLUTION",),
1233        **dict.fromkeys(("BINDING", "COMPENSATION", "EVOLUTION"), tuple()),
1234    }
1235
1236    PROCEDURE_OPTIONS: OPTIONS_TYPE = {}
1237
1238    EXECUTE_AS_OPTIONS: OPTIONS_TYPE = dict.fromkeys(("CALLER", "SELF", "OWNER"), tuple())
1239
1240    KEY_CONSTRAINT_OPTIONS: OPTIONS_TYPE = {
1241        "NOT": ("ENFORCED",),
1242        "MATCH": (
1243            "FULL",
1244            "PARTIAL",
1245            "SIMPLE",
1246        ),
1247        "INITIALLY": ("DEFERRED", "IMMEDIATE"),
1248        **dict.fromkeys(("DEFERRABLE", "NORELY"), tuple()),
1249    }
1250
1251    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
1252
1253    CLONE_KEYWORDS = {"CLONE", "COPY"}
1254    HISTORICAL_DATA_PREFIX = {"AT", "BEFORE", "END"}
1255    HISTORICAL_DATA_KIND = {"TIMESTAMP", "OFFSET", "STATEMENT", "STREAM"}
1256
1257    OPCLASS_FOLLOW_KEYWORDS = {"ASC", "DESC", "NULLS", "WITH"}
1258
1259    OPTYPE_FOLLOW_TOKENS = {TokenType.COMMA, TokenType.R_PAREN}
1260
1261    TABLE_INDEX_HINT_TOKENS = {TokenType.FORCE, TokenType.IGNORE, TokenType.USE}
1262
1263    VIEW_ATTRIBUTES = {"ENCRYPTION", "SCHEMABINDING", "VIEW_METADATA"}
1264
1265    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
1266    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
1267    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
1268
1269    JSON_KEY_VALUE_SEPARATOR_TOKENS = {TokenType.COLON, TokenType.COMMA, TokenType.IS}
1270
1271    FETCH_TOKENS = ID_VAR_TOKENS - {TokenType.ROW, TokenType.ROWS, TokenType.PERCENT}
1272
1273    ADD_CONSTRAINT_TOKENS = {
1274        TokenType.CONSTRAINT,
1275        TokenType.FOREIGN_KEY,
1276        TokenType.INDEX,
1277        TokenType.KEY,
1278        TokenType.PRIMARY_KEY,
1279        TokenType.UNIQUE,
1280    }
1281
1282    DISTINCT_TOKENS = {TokenType.DISTINCT}
1283
1284    NULL_TOKENS = {TokenType.NULL}
1285
1286    UNNEST_OFFSET_ALIAS_TOKENS = ID_VAR_TOKENS - SET_OPERATIONS
1287
1288    SELECT_START_TOKENS = {TokenType.L_PAREN, TokenType.WITH, TokenType.SELECT}
1289
1290    COPY_INTO_VARLEN_OPTIONS = {"FILE_FORMAT", "COPY_OPTIONS", "FORMAT_OPTIONS", "CREDENTIAL"}
1291
1292    IS_JSON_PREDICATE_KIND = {"VALUE", "SCALAR", "ARRAY", "OBJECT"}
1293
1294    ODBC_DATETIME_LITERALS = {
1295        "d": exp.Date,
1296        "t": exp.Time,
1297        "ts": exp.Timestamp,
1298    }
1299
1300    ON_CONDITION_TOKENS = {"ERROR", "NULL", "TRUE", "FALSE", "EMPTY"}
1301
1302    PRIVILEGE_FOLLOW_TOKENS = {TokenType.ON, TokenType.COMMA, TokenType.L_PAREN}
1303
1304    # The style options for the DESCRIBE statement
1305    DESCRIBE_STYLES = {"ANALYZE", "EXTENDED", "FORMATTED", "HISTORY"}
1306
1307    OPERATION_MODIFIERS: t.Set[str] = set()
1308
1309    STRICT_CAST = True
1310
1311    PREFIXED_PIVOT_COLUMNS = False
1312    IDENTIFY_PIVOT_STRINGS = False
1313
1314    LOG_DEFAULTS_TO_LN = False
1315
1316    # Whether ADD is present for each column added by ALTER TABLE
1317    ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
1318
1319    # Whether the table sample clause expects CSV syntax
1320    TABLESAMPLE_CSV = False
1321
1322    # The default method used for table sampling
1323    DEFAULT_SAMPLING_METHOD: t.Optional[str] = None
1324
1325    # Whether the SET command needs a delimiter (e.g. "=") for assignments
1326    SET_REQUIRES_ASSIGNMENT_DELIMITER = True
1327
1328    # Whether the TRIM function expects the characters to trim as its first argument
1329    TRIM_PATTERN_FIRST = False
1330
1331    # Whether string aliases are supported `SELECT COUNT(*) 'count'`
1332    STRING_ALIASES = False
1333
1334    # Whether query modifiers such as LIMIT are attached to the UNION node (vs its right operand)
1335    MODIFIERS_ATTACHED_TO_SET_OP = True
1336    SET_OP_MODIFIERS = {"order", "limit", "offset"}
1337
1338    # Whether to parse IF statements that aren't followed by a left parenthesis as commands
1339    NO_PAREN_IF_COMMANDS = True
1340
1341    # Whether the -> and ->> operators expect documents of type JSON (e.g. Postgres)
1342    JSON_ARROWS_REQUIRE_JSON_TYPE = False
1343
1344    # Whether the `:` operator is used to extract a value from a VARIANT column
1345    COLON_IS_VARIANT_EXTRACT = False
1346
1347    # Whether or not a VALUES keyword needs to be followed by '(' to form a VALUES clause.
1348    # If this is True and '(' is not found, the keyword will be treated as an identifier
1349    VALUES_FOLLOWED_BY_PAREN = True
1350
1351    # Whether implicit unnesting is supported, e.g. SELECT 1 FROM y.z AS z, z.a (Redshift)
1352    SUPPORTS_IMPLICIT_UNNEST = False
1353
1354    # Whether or not interval spans are supported, INTERVAL 1 YEAR TO MONTHS
1355    INTERVAL_SPANS = True
1356
1357    # Whether a PARTITION clause can follow a table reference
1358    SUPPORTS_PARTITION_SELECTION = False
1359
1360    __slots__ = (
1361        "error_level",
1362        "error_message_context",
1363        "max_errors",
1364        "dialect",
1365        "sql",
1366        "errors",
1367        "_tokens",
1368        "_index",
1369        "_curr",
1370        "_next",
1371        "_prev",
1372        "_prev_comments",
1373    )
1374
1375    # Autofilled
1376    SHOW_TRIE: t.Dict = {}
1377    SET_TRIE: t.Dict = {}
1378
1379    def __init__(
1380        self,
1381        error_level: t.Optional[ErrorLevel] = None,
1382        error_message_context: int = 100,
1383        max_errors: int = 3,
1384        dialect: DialectType = None,
1385    ):
1386        from sqlglot.dialects import Dialect
1387
1388        self.error_level = error_level or ErrorLevel.IMMEDIATE
1389        self.error_message_context = error_message_context
1390        self.max_errors = max_errors
1391        self.dialect = Dialect.get_or_raise(dialect)
1392        self.reset()
1393
1394    def reset(self):
1395        self.sql = ""
1396        self.errors = []
1397        self._tokens = []
1398        self._index = 0
1399        self._curr = None
1400        self._next = None
1401        self._prev = None
1402        self._prev_comments = None
1403
1404    def parse(
1405        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1406    ) -> t.List[t.Optional[exp.Expression]]:
1407        """
1408        Parses a list of tokens and returns a list of syntax trees, one tree
1409        per parsed SQL statement.
1410
1411        Args:
1412            raw_tokens: The list of tokens.
1413            sql: The original SQL string, used to produce helpful debug messages.
1414
1415        Returns:
1416            The list of the produced syntax trees.
1417        """
1418        return self._parse(
1419            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1420        )
1421
1422    def parse_into(
1423        self,
1424        expression_types: exp.IntoType,
1425        raw_tokens: t.List[Token],
1426        sql: t.Optional[str] = None,
1427    ) -> t.List[t.Optional[exp.Expression]]:
1428        """
1429        Parses a list of tokens into a given Expression type. If a collection of Expression
1430        types is given instead, this method will try to parse the token list into each one
1431        of them, stopping at the first for which the parsing succeeds.
1432
1433        Args:
1434            expression_types: The expression type(s) to try and parse the token list into.
1435            raw_tokens: The list of tokens.
1436            sql: The original SQL string, used to produce helpful debug messages.
1437
1438        Returns:
1439            The target Expression.
1440        """
1441        errors = []
1442        for expression_type in ensure_list(expression_types):
1443            parser = self.EXPRESSION_PARSERS.get(expression_type)
1444            if not parser:
1445                raise TypeError(f"No parser registered for {expression_type}")
1446
1447            try:
1448                return self._parse(parser, raw_tokens, sql)
1449            except ParseError as e:
1450                e.errors[0]["into_expression"] = expression_type
1451                errors.append(e)
1452
1453        raise ParseError(
1454            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1455            errors=merge_errors(errors),
1456        ) from errors[-1]
1457
1458    def _parse(
1459        self,
1460        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
1461        raw_tokens: t.List[Token],
1462        sql: t.Optional[str] = None,
1463    ) -> t.List[t.Optional[exp.Expression]]:
1464        self.reset()
1465        self.sql = sql or ""
1466
1467        total = len(raw_tokens)
1468        chunks: t.List[t.List[Token]] = [[]]
1469
1470        for i, token in enumerate(raw_tokens):
1471            if token.token_type == TokenType.SEMICOLON:
1472                if token.comments:
1473                    chunks.append([token])
1474
1475                if i < total - 1:
1476                    chunks.append([])
1477            else:
1478                chunks[-1].append(token)
1479
1480        expressions = []
1481
1482        for tokens in chunks:
1483            self._index = -1
1484            self._tokens = tokens
1485            self._advance()
1486
1487            expressions.append(parse_method(self))
1488
1489            if self._index < len(self._tokens):
1490                self.raise_error("Invalid expression / Unexpected token")
1491
1492            self.check_errors()
1493
1494        return expressions
1495
1496    def check_errors(self) -> None:
1497        """Logs or raises any found errors, depending on the chosen error level setting."""
1498        if self.error_level == ErrorLevel.WARN:
1499            for error in self.errors:
1500                logger.error(str(error))
1501        elif self.error_level == ErrorLevel.RAISE and self.errors:
1502            raise ParseError(
1503                concat_messages(self.errors, self.max_errors),
1504                errors=merge_errors(self.errors),
1505            )
1506
1507    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1508        """
1509        Appends an error in the list of recorded errors or raises it, depending on the chosen
1510        error level setting.
1511        """
1512        token = token or self._curr or self._prev or Token.string("")
1513        start = token.start
1514        end = token.end + 1
1515        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1516        highlight = self.sql[start:end]
1517        end_context = self.sql[end : end + self.error_message_context]
1518
1519        error = ParseError.new(
1520            f"{message}. Line {token.line}, Col: {token.col}.\n"
1521            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1522            description=message,
1523            line=token.line,
1524            col=token.col,
1525            start_context=start_context,
1526            highlight=highlight,
1527            end_context=end_context,
1528        )
1529
1530        if self.error_level == ErrorLevel.IMMEDIATE:
1531            raise error
1532
1533        self.errors.append(error)
1534
1535    def expression(
1536        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1537    ) -> E:
1538        """
1539        Creates a new, validated Expression.
1540
1541        Args:
1542            exp_class: The expression class to instantiate.
1543            comments: An optional list of comments to attach to the expression.
1544            kwargs: The arguments to set for the expression along with their respective values.
1545
1546        Returns:
1547            The target expression.
1548        """
1549        instance = exp_class(**kwargs)
1550        instance.add_comments(comments) if comments else self._add_comments(instance)
1551        return self.validate_expression(instance)
1552
1553    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
1554        if expression and self._prev_comments:
1555            expression.add_comments(self._prev_comments)
1556            self._prev_comments = None
1557
1558    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1559        """
1560        Validates an Expression, making sure that all its mandatory arguments are set.
1561
1562        Args:
1563            expression: The expression to validate.
1564            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1565
1566        Returns:
1567            The validated expression.
1568        """
1569        if self.error_level != ErrorLevel.IGNORE:
1570            for error_message in expression.error_messages(args):
1571                self.raise_error(error_message)
1572
1573        return expression
1574
1575    def _find_sql(self, start: Token, end: Token) -> str:
1576        return self.sql[start.start : end.end + 1]
1577
1578    def _is_connected(self) -> bool:
1579        return self._prev and self._curr and self._prev.end + 1 == self._curr.start
1580
1581    def _advance(self, times: int = 1) -> None:
1582        self._index += times
1583        self._curr = seq_get(self._tokens, self._index)
1584        self._next = seq_get(self._tokens, self._index + 1)
1585
1586        if self._index > 0:
1587            self._prev = self._tokens[self._index - 1]
1588            self._prev_comments = self._prev.comments
1589        else:
1590            self._prev = None
1591            self._prev_comments = None
1592
1593    def _retreat(self, index: int) -> None:
1594        if index != self._index:
1595            self._advance(index - self._index)
1596
1597    def _warn_unsupported(self) -> None:
1598        if len(self._tokens) <= 1:
1599            return
1600
1601        # We use _find_sql because self.sql may comprise multiple chunks, and we're only
1602        # interested in emitting a warning for the one being currently processed.
1603        sql = self._find_sql(self._tokens[0], self._tokens[-1])[: self.error_message_context]
1604
1605        logger.warning(
1606            f"'{sql}' contains unsupported syntax. Falling back to parsing as a 'Command'."
1607        )
1608
1609    def _parse_command(self) -> exp.Command:
1610        self._warn_unsupported()
1611        return self.expression(
1612            exp.Command,
1613            comments=self._prev_comments,
1614            this=self._prev.text.upper(),
1615            expression=self._parse_string(),
1616        )
1617
1618    def _try_parse(self, parse_method: t.Callable[[], T], retreat: bool = False) -> t.Optional[T]:
1619        """
1620        Attemps to backtrack if a parse function that contains a try/catch internally raises an error.
1621        This behavior can be different depending on the uset-set ErrorLevel, so _try_parse aims to
1622        solve this by setting & resetting the parser state accordingly
1623        """
1624        index = self._index
1625        error_level = self.error_level
1626
1627        self.error_level = ErrorLevel.IMMEDIATE
1628        try:
1629            this = parse_method()
1630        except ParseError:
1631            this = None
1632        finally:
1633            if not this or retreat:
1634                self._retreat(index)
1635            self.error_level = error_level
1636
1637        return this
1638
1639    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
1640        start = self._prev
1641        exists = self._parse_exists() if allow_exists else None
1642
1643        self._match(TokenType.ON)
1644
1645        materialized = self._match_text_seq("MATERIALIZED")
1646        kind = self._match_set(self.CREATABLES) and self._prev
1647        if not kind:
1648            return self._parse_as_command(start)
1649
1650        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1651            this = self._parse_user_defined_function(kind=kind.token_type)
1652        elif kind.token_type == TokenType.TABLE:
1653            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
1654        elif kind.token_type == TokenType.COLUMN:
1655            this = self._parse_column()
1656        else:
1657            this = self._parse_id_var()
1658
1659        self._match(TokenType.IS)
1660
1661        return self.expression(
1662            exp.Comment,
1663            this=this,
1664            kind=kind.text,
1665            expression=self._parse_string(),
1666            exists=exists,
1667            materialized=materialized,
1668        )
1669
1670    def _parse_to_table(
1671        self,
1672    ) -> exp.ToTableProperty:
1673        table = self._parse_table_parts(schema=True)
1674        return self.expression(exp.ToTableProperty, this=table)
1675
1676    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
1677    def _parse_ttl(self) -> exp.Expression:
1678        def _parse_ttl_action() -> t.Optional[exp.Expression]:
1679            this = self._parse_bitwise()
1680
1681            if self._match_text_seq("DELETE"):
1682                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
1683            if self._match_text_seq("RECOMPRESS"):
1684                return self.expression(
1685                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
1686                )
1687            if self._match_text_seq("TO", "DISK"):
1688                return self.expression(
1689                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
1690                )
1691            if self._match_text_seq("TO", "VOLUME"):
1692                return self.expression(
1693                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
1694                )
1695
1696            return this
1697
1698        expressions = self._parse_csv(_parse_ttl_action)
1699        where = self._parse_where()
1700        group = self._parse_group()
1701
1702        aggregates = None
1703        if group and self._match(TokenType.SET):
1704            aggregates = self._parse_csv(self._parse_set_item)
1705
1706        return self.expression(
1707            exp.MergeTreeTTL,
1708            expressions=expressions,
1709            where=where,
1710            group=group,
1711            aggregates=aggregates,
1712        )
1713
1714    def _parse_statement(self) -> t.Optional[exp.Expression]:
1715        if self._curr is None:
1716            return None
1717
1718        if self._match_set(self.STATEMENT_PARSERS):
1719            return self.STATEMENT_PARSERS[self._prev.token_type](self)
1720
1721        if self._match_set(self.dialect.tokenizer.COMMANDS):
1722            return self._parse_command()
1723
1724        expression = self._parse_expression()
1725        expression = self._parse_set_operations(expression) if expression else self._parse_select()
1726        return self._parse_query_modifiers(expression)
1727
1728    def _parse_drop(self, exists: bool = False) -> exp.Drop | exp.Command:
1729        start = self._prev
1730        temporary = self._match(TokenType.TEMPORARY)
1731        materialized = self._match_text_seq("MATERIALIZED")
1732
1733        kind = self._match_set(self.CREATABLES) and self._prev.text.upper()
1734        if not kind:
1735            return self._parse_as_command(start)
1736
1737        concurrently = self._match_text_seq("CONCURRENTLY")
1738        if_exists = exists or self._parse_exists()
1739        table = self._parse_table_parts(
1740            schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
1741        )
1742
1743        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
1744
1745        if self._match(TokenType.L_PAREN, advance=False):
1746            expressions = self._parse_wrapped_csv(self._parse_types)
1747        else:
1748            expressions = None
1749
1750        return self.expression(
1751            exp.Drop,
1752            comments=start.comments,
1753            exists=if_exists,
1754            this=table,
1755            expressions=expressions,
1756            kind=self.dialect.CREATABLE_KIND_MAPPING.get(kind) or kind,
1757            temporary=temporary,
1758            materialized=materialized,
1759            cascade=self._match_text_seq("CASCADE"),
1760            constraints=self._match_text_seq("CONSTRAINTS"),
1761            purge=self._match_text_seq("PURGE"),
1762            cluster=cluster,
1763            concurrently=concurrently,
1764        )
1765
1766    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
1767        return (
1768            self._match_text_seq("IF")
1769            and (not not_ or self._match(TokenType.NOT))
1770            and self._match(TokenType.EXISTS)
1771        )
1772
1773    def _parse_create(self) -> exp.Create | exp.Command:
1774        # Note: this can't be None because we've matched a statement parser
1775        start = self._prev
1776        comments = self._prev_comments
1777
1778        replace = (
1779            start.token_type == TokenType.REPLACE
1780            or self._match_pair(TokenType.OR, TokenType.REPLACE)
1781            or self._match_pair(TokenType.OR, TokenType.ALTER)
1782        )
1783        refresh = self._match_pair(TokenType.OR, TokenType.REFRESH)
1784
1785        unique = self._match(TokenType.UNIQUE)
1786
1787        if self._match_text_seq("CLUSTERED", "COLUMNSTORE"):
1788            clustered = True
1789        elif self._match_text_seq("NONCLUSTERED", "COLUMNSTORE") or self._match_text_seq(
1790            "COLUMNSTORE"
1791        ):
1792            clustered = False
1793        else:
1794            clustered = None
1795
1796        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
1797            self._advance()
1798
1799        properties = None
1800        create_token = self._match_set(self.CREATABLES) and self._prev
1801
1802        if not create_token:
1803            # exp.Properties.Location.POST_CREATE
1804            properties = self._parse_properties()
1805            create_token = self._match_set(self.CREATABLES) and self._prev
1806
1807            if not properties or not create_token:
1808                return self._parse_as_command(start)
1809
1810        concurrently = self._match_text_seq("CONCURRENTLY")
1811        exists = self._parse_exists(not_=True)
1812        this = None
1813        expression: t.Optional[exp.Expression] = None
1814        indexes = None
1815        no_schema_binding = None
1816        begin = None
1817        end = None
1818        clone = None
1819
1820        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
1821            nonlocal properties
1822            if properties and temp_props:
1823                properties.expressions.extend(temp_props.expressions)
1824            elif temp_props:
1825                properties = temp_props
1826
1827        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1828            this = self._parse_user_defined_function(kind=create_token.token_type)
1829
1830            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
1831            extend_props(self._parse_properties())
1832
1833            expression = self._match(TokenType.ALIAS) and self._parse_heredoc()
1834            extend_props(self._parse_properties())
1835
1836            if not expression:
1837                if self._match(TokenType.COMMAND):
1838                    expression = self._parse_as_command(self._prev)
1839                else:
1840                    begin = self._match(TokenType.BEGIN)
1841                    return_ = self._match_text_seq("RETURN")
1842
1843                    if self._match(TokenType.STRING, advance=False):
1844                        # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
1845                        # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
1846                        expression = self._parse_string()
1847                        extend_props(self._parse_properties())
1848                    else:
1849                        expression = self._parse_user_defined_function_expression()
1850
1851                    end = self._match_text_seq("END")
1852
1853                    if return_:
1854                        expression = self.expression(exp.Return, this=expression)
1855        elif create_token.token_type == TokenType.INDEX:
1856            # Postgres allows anonymous indexes, eg. CREATE INDEX IF NOT EXISTS ON t(c)
1857            if not self._match(TokenType.ON):
1858                index = self._parse_id_var()
1859                anonymous = False
1860            else:
1861                index = None
1862                anonymous = True
1863
1864            this = self._parse_index(index=index, anonymous=anonymous)
1865        elif create_token.token_type in self.DB_CREATABLES:
1866            table_parts = self._parse_table_parts(
1867                schema=True, is_db_reference=create_token.token_type == TokenType.SCHEMA
1868            )
1869
1870            # exp.Properties.Location.POST_NAME
1871            self._match(TokenType.COMMA)
1872            extend_props(self._parse_properties(before=True))
1873
1874            this = self._parse_schema(this=table_parts)
1875
1876            # exp.Properties.Location.POST_SCHEMA and POST_WITH
1877            extend_props(self._parse_properties())
1878
1879            self._match(TokenType.ALIAS)
1880            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
1881                # exp.Properties.Location.POST_ALIAS
1882                extend_props(self._parse_properties())
1883
1884            if create_token.token_type == TokenType.SEQUENCE:
1885                expression = self._parse_types()
1886                extend_props(self._parse_properties())
1887            else:
1888                expression = self._parse_ddl_select()
1889
1890            if create_token.token_type == TokenType.TABLE:
1891                # exp.Properties.Location.POST_EXPRESSION
1892                extend_props(self._parse_properties())
1893
1894                indexes = []
1895                while True:
1896                    index = self._parse_index()
1897
1898                    # exp.Properties.Location.POST_INDEX
1899                    extend_props(self._parse_properties())
1900                    if not index:
1901                        break
1902                    else:
1903                        self._match(TokenType.COMMA)
1904                        indexes.append(index)
1905            elif create_token.token_type == TokenType.VIEW:
1906                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
1907                    no_schema_binding = True
1908
1909            shallow = self._match_text_seq("SHALLOW")
1910
1911            if self._match_texts(self.CLONE_KEYWORDS):
1912                copy = self._prev.text.lower() == "copy"
1913                clone = self.expression(
1914                    exp.Clone, this=self._parse_table(schema=True), shallow=shallow, copy=copy
1915                )
1916
1917        if self._curr and not self._match_set((TokenType.R_PAREN, TokenType.COMMA), advance=False):
1918            return self._parse_as_command(start)
1919
1920        create_kind_text = create_token.text.upper()
1921        return self.expression(
1922            exp.Create,
1923            comments=comments,
1924            this=this,
1925            kind=self.dialect.CREATABLE_KIND_MAPPING.get(create_kind_text) or create_kind_text,
1926            replace=replace,
1927            refresh=refresh,
1928            unique=unique,
1929            expression=expression,
1930            exists=exists,
1931            properties=properties,
1932            indexes=indexes,
1933            no_schema_binding=no_schema_binding,
1934            begin=begin,
1935            end=end,
1936            clone=clone,
1937            concurrently=concurrently,
1938            clustered=clustered,
1939        )
1940
1941    def _parse_sequence_properties(self) -> t.Optional[exp.SequenceProperties]:
1942        seq = exp.SequenceProperties()
1943
1944        options = []
1945        index = self._index
1946
1947        while self._curr:
1948            self._match(TokenType.COMMA)
1949            if self._match_text_seq("INCREMENT"):
1950                self._match_text_seq("BY")
1951                self._match_text_seq("=")
1952                seq.set("increment", self._parse_term())
1953            elif self._match_text_seq("MINVALUE"):
1954                seq.set("minvalue", self._parse_term())
1955            elif self._match_text_seq("MAXVALUE"):
1956                seq.set("maxvalue", self._parse_term())
1957            elif self._match(TokenType.START_WITH) or self._match_text_seq("START"):
1958                self._match_text_seq("=")
1959                seq.set("start", self._parse_term())
1960            elif self._match_text_seq("CACHE"):
1961                # T-SQL allows empty CACHE which is initialized dynamically
1962                seq.set("cache", self._parse_number() or True)
1963            elif self._match_text_seq("OWNED", "BY"):
1964                # "OWNED BY NONE" is the default
1965                seq.set("owned", None if self._match_text_seq("NONE") else self._parse_column())
1966            else:
1967                opt = self._parse_var_from_options(self.CREATE_SEQUENCE, raise_unmatched=False)
1968                if opt:
1969                    options.append(opt)
1970                else:
1971                    break
1972
1973        seq.set("options", options if options else None)
1974        return None if self._index == index else seq
1975
1976    def _parse_property_before(self) -> t.Optional[exp.Expression]:
1977        # only used for teradata currently
1978        self._match(TokenType.COMMA)
1979
1980        kwargs = {
1981            "no": self._match_text_seq("NO"),
1982            "dual": self._match_text_seq("DUAL"),
1983            "before": self._match_text_seq("BEFORE"),
1984            "default": self._match_text_seq("DEFAULT"),
1985            "local": (self._match_text_seq("LOCAL") and "LOCAL")
1986            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
1987            "after": self._match_text_seq("AFTER"),
1988            "minimum": self._match_texts(("MIN", "MINIMUM")),
1989            "maximum": self._match_texts(("MAX", "MAXIMUM")),
1990        }
1991
1992        if self._match_texts(self.PROPERTY_PARSERS):
1993            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
1994            try:
1995                return parser(self, **{k: v for k, v in kwargs.items() if v})
1996            except TypeError:
1997                self.raise_error(f"Cannot parse property '{self._prev.text}'")
1998
1999        return None
2000
2001    def _parse_wrapped_properties(self) -> t.List[exp.Expression]:
2002        return self._parse_wrapped_csv(self._parse_property)
2003
2004    def _parse_property(self) -> t.Optional[exp.Expression]:
2005        if self._match_texts(self.PROPERTY_PARSERS):
2006            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
2007
2008        if self._match(TokenType.DEFAULT) and self._match_texts(self.PROPERTY_PARSERS):
2009            return self.PROPERTY_PARSERS[self._prev.text.upper()](self, default=True)
2010
2011        if self._match_text_seq("COMPOUND", "SORTKEY"):
2012            return self._parse_sortkey(compound=True)
2013
2014        if self._match_text_seq("SQL", "SECURITY"):
2015            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
2016
2017        index = self._index
2018        key = self._parse_column()
2019
2020        if not self._match(TokenType.EQ):
2021            self._retreat(index)
2022            return self._parse_sequence_properties()
2023
2024        # Transform the key to exp.Dot if it's dotted identifiers wrapped in exp.Column or to exp.Var otherwise
2025        if isinstance(key, exp.Column):
2026            key = key.to_dot() if len(key.parts) > 1 else exp.var(key.name)
2027
2028        value = self._parse_bitwise() or self._parse_var(any_token=True)
2029
2030        # Transform the value to exp.Var if it was parsed as exp.Column(exp.Identifier())
2031        if isinstance(value, exp.Column):
2032            value = exp.var(value.name)
2033
2034        return self.expression(exp.Property, this=key, value=value)
2035
2036    def _parse_stored(self) -> exp.FileFormatProperty:
2037        self._match(TokenType.ALIAS)
2038
2039        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
2040        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
2041
2042        return self.expression(
2043            exp.FileFormatProperty,
2044            this=(
2045                self.expression(
2046                    exp.InputOutputFormat, input_format=input_format, output_format=output_format
2047                )
2048                if input_format or output_format
2049                else self._parse_var_or_string() or self._parse_number() or self._parse_id_var()
2050            ),
2051        )
2052
2053    def _parse_unquoted_field(self) -> t.Optional[exp.Expression]:
2054        field = self._parse_field()
2055        if isinstance(field, exp.Identifier) and not field.quoted:
2056            field = exp.var(field)
2057
2058        return field
2059
2060    def _parse_property_assignment(self, exp_class: t.Type[E], **kwargs: t.Any) -> E:
2061        self._match(TokenType.EQ)
2062        self._match(TokenType.ALIAS)
2063
2064        return self.expression(exp_class, this=self._parse_unquoted_field(), **kwargs)
2065
2066    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
2067        properties = []
2068        while True:
2069            if before:
2070                prop = self._parse_property_before()
2071            else:
2072                prop = self._parse_property()
2073            if not prop:
2074                break
2075            for p in ensure_list(prop):
2076                properties.append(p)
2077
2078        if properties:
2079            return self.expression(exp.Properties, expressions=properties)
2080
2081        return None
2082
2083    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
2084        return self.expression(
2085            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
2086        )
2087
2088    def _parse_security(self) -> t.Optional[exp.SecurityProperty]:
2089        if self._match_texts(("DEFINER", "INVOKER")):
2090            security_specifier = self._prev.text.upper()
2091            return self.expression(exp.SecurityProperty, this=security_specifier)
2092        return None
2093
2094    def _parse_settings_property(self) -> exp.SettingsProperty:
2095        return self.expression(
2096            exp.SettingsProperty, expressions=self._parse_csv(self._parse_assignment)
2097        )
2098
2099    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
2100        if self._index >= 2:
2101            pre_volatile_token = self._tokens[self._index - 2]
2102        else:
2103            pre_volatile_token = None
2104
2105        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
2106            return exp.VolatileProperty()
2107
2108        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
2109
2110    def _parse_retention_period(self) -> exp.Var:
2111        # Parse TSQL's HISTORY_RETENTION_PERIOD: {INFINITE | <number> DAY | DAYS | MONTH ...}
2112        number = self._parse_number()
2113        number_str = f"{number} " if number else ""
2114        unit = self._parse_var(any_token=True)
2115        return exp.var(f"{number_str}{unit}")
2116
2117    def _parse_system_versioning_property(
2118        self, with_: bool = False
2119    ) -> exp.WithSystemVersioningProperty:
2120        self._match(TokenType.EQ)
2121        prop = self.expression(
2122            exp.WithSystemVersioningProperty,
2123            **{  # type: ignore
2124                "on": True,
2125                "with": with_,
2126            },
2127        )
2128
2129        if self._match_text_seq("OFF"):
2130            prop.set("on", False)
2131            return prop
2132
2133        self._match(TokenType.ON)
2134        if self._match(TokenType.L_PAREN):
2135            while self._curr and not self._match(TokenType.R_PAREN):
2136                if self._match_text_seq("HISTORY_TABLE", "="):
2137                    prop.set("this", self._parse_table_parts())
2138                elif self._match_text_seq("DATA_CONSISTENCY_CHECK", "="):
2139                    prop.set("data_consistency", self._advance_any() and self._prev.text.upper())
2140                elif self._match_text_seq("HISTORY_RETENTION_PERIOD", "="):
2141                    prop.set("retention_period", self._parse_retention_period())
2142
2143                self._match(TokenType.COMMA)
2144
2145        return prop
2146
2147    def _parse_data_deletion_property(self) -> exp.DataDeletionProperty:
2148        self._match(TokenType.EQ)
2149        on = self._match_text_seq("ON") or not self._match_text_seq("OFF")
2150        prop = self.expression(exp.DataDeletionProperty, on=on)
2151
2152        if self._match(TokenType.L_PAREN):
2153            while self._curr and not self._match(TokenType.R_PAREN):
2154                if self._match_text_seq("FILTER_COLUMN", "="):
2155                    prop.set("filter_column", self._parse_column())
2156                elif self._match_text_seq("RETENTION_PERIOD", "="):
2157                    prop.set("retention_period", self._parse_retention_period())
2158
2159                self._match(TokenType.COMMA)
2160
2161        return prop
2162
2163    def _parse_distributed_property(self) -> exp.DistributedByProperty:
2164        kind = "HASH"
2165        expressions: t.Optional[t.List[exp.Expression]] = None
2166        if self._match_text_seq("BY", "HASH"):
2167            expressions = self._parse_wrapped_csv(self._parse_id_var)
2168        elif self._match_text_seq("BY", "RANDOM"):
2169            kind = "RANDOM"
2170
2171        # If the BUCKETS keyword is not present, the number of buckets is AUTO
2172        buckets: t.Optional[exp.Expression] = None
2173        if self._match_text_seq("BUCKETS") and not self._match_text_seq("AUTO"):
2174            buckets = self._parse_number()
2175
2176        return self.expression(
2177            exp.DistributedByProperty,
2178            expressions=expressions,
2179            kind=kind,
2180            buckets=buckets,
2181            order=self._parse_order(),
2182        )
2183
2184    def _parse_duplicate(self) -> exp.DuplicateKeyProperty:
2185        self._match_text_seq("KEY")
2186        expressions = self._parse_wrapped_csv(self._parse_id_var, optional=False)
2187        return self.expression(exp.DuplicateKeyProperty, expressions=expressions)
2188
2189    def _parse_with_property(self) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
2190        if self._match_text_seq("(", "SYSTEM_VERSIONING"):
2191            prop = self._parse_system_versioning_property(with_=True)
2192            self._match_r_paren()
2193            return prop
2194
2195        if self._match(TokenType.L_PAREN, advance=False):
2196            return self._parse_wrapped_properties()
2197
2198        if self._match_text_seq("JOURNAL"):
2199            return self._parse_withjournaltable()
2200
2201        if self._match_texts(self.VIEW_ATTRIBUTES):
2202            return self.expression(exp.ViewAttributeProperty, this=self._prev.text.upper())
2203
2204        if self._match_text_seq("DATA"):
2205            return self._parse_withdata(no=False)
2206        elif self._match_text_seq("NO", "DATA"):
2207            return self._parse_withdata(no=True)
2208
2209        if self._match(TokenType.SERDE_PROPERTIES, advance=False):
2210            return self._parse_serde_properties(with_=True)
2211
2212        if self._match(TokenType.SCHEMA):
2213            return self.expression(
2214                exp.WithSchemaBindingProperty,
2215                this=self._parse_var_from_options(self.SCHEMA_BINDING_OPTIONS),
2216            )
2217
2218        if self._match_texts(self.PROCEDURE_OPTIONS, advance=False):
2219            return self.expression(
2220                exp.WithProcedureOptions, expressions=self._parse_csv(self._parse_procedure_option)
2221            )
2222
2223        if not self._next:
2224            return None
2225
2226        return self._parse_withisolatedloading()
2227
2228    def _parse_procedure_option(self) -> exp.Expression | None:
2229        if self._match_text_seq("EXECUTE", "AS"):
2230            return self.expression(
2231                exp.ExecuteAsProperty,
2232                this=self._parse_var_from_options(self.EXECUTE_AS_OPTIONS, raise_unmatched=False)
2233                or self._parse_string(),
2234            )
2235
2236        return self._parse_var_from_options(self.PROCEDURE_OPTIONS)
2237
2238    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
2239    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
2240        self._match(TokenType.EQ)
2241
2242        user = self._parse_id_var()
2243        self._match(TokenType.PARAMETER)
2244        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
2245
2246        if not user or not host:
2247            return None
2248
2249        return exp.DefinerProperty(this=f"{user}@{host}")
2250
2251    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
2252        self._match(TokenType.TABLE)
2253        self._match(TokenType.EQ)
2254        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
2255
2256    def _parse_log(self, no: bool = False) -> exp.LogProperty:
2257        return self.expression(exp.LogProperty, no=no)
2258
2259    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
2260        return self.expression(exp.JournalProperty, **kwargs)
2261
2262    def _parse_checksum(self) -> exp.ChecksumProperty:
2263        self._match(TokenType.EQ)
2264
2265        on = None
2266        if self._match(TokenType.ON):
2267            on = True
2268        elif self._match_text_seq("OFF"):
2269            on = False
2270
2271        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
2272
2273    def _parse_cluster(self, wrapped: bool = False) -> exp.Cluster:
2274        return self.expression(
2275            exp.Cluster,
2276            expressions=(
2277                self._parse_wrapped_csv(self._parse_ordered)
2278                if wrapped
2279                else self._parse_csv(self._parse_ordered)
2280            ),
2281        )
2282
2283    def _parse_clustered_by(self) -> exp.ClusteredByProperty:
2284        self._match_text_seq("BY")
2285
2286        self._match_l_paren()
2287        expressions = self._parse_csv(self._parse_column)
2288        self._match_r_paren()
2289
2290        if self._match_text_seq("SORTED", "BY"):
2291            self._match_l_paren()
2292            sorted_by = self._parse_csv(self._parse_ordered)
2293            self._match_r_paren()
2294        else:
2295            sorted_by = None
2296
2297        self._match(TokenType.INTO)
2298        buckets = self._parse_number()
2299        self._match_text_seq("BUCKETS")
2300
2301        return self.expression(
2302            exp.ClusteredByProperty,
2303            expressions=expressions,
2304            sorted_by=sorted_by,
2305            buckets=buckets,
2306        )
2307
2308    def _parse_copy_property(self) -> t.Optional[exp.CopyGrantsProperty]:
2309        if not self._match_text_seq("GRANTS"):
2310            self._retreat(self._index - 1)
2311            return None
2312
2313        return self.expression(exp.CopyGrantsProperty)
2314
2315    def _parse_freespace(self) -> exp.FreespaceProperty:
2316        self._match(TokenType.EQ)
2317        return self.expression(
2318            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
2319        )
2320
2321    def _parse_mergeblockratio(
2322        self, no: bool = False, default: bool = False
2323    ) -> exp.MergeBlockRatioProperty:
2324        if self._match(TokenType.EQ):
2325            return self.expression(
2326                exp.MergeBlockRatioProperty,
2327                this=self._parse_number(),
2328                percent=self._match(TokenType.PERCENT),
2329            )
2330
2331        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
2332
2333    def _parse_datablocksize(
2334        self,
2335        default: t.Optional[bool] = None,
2336        minimum: t.Optional[bool] = None,
2337        maximum: t.Optional[bool] = None,
2338    ) -> exp.DataBlocksizeProperty:
2339        self._match(TokenType.EQ)
2340        size = self._parse_number()
2341
2342        units = None
2343        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
2344            units = self._prev.text
2345
2346        return self.expression(
2347            exp.DataBlocksizeProperty,
2348            size=size,
2349            units=units,
2350            default=default,
2351            minimum=minimum,
2352            maximum=maximum,
2353        )
2354
2355    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
2356        self._match(TokenType.EQ)
2357        always = self._match_text_seq("ALWAYS")
2358        manual = self._match_text_seq("MANUAL")
2359        never = self._match_text_seq("NEVER")
2360        default = self._match_text_seq("DEFAULT")
2361
2362        autotemp = None
2363        if self._match_text_seq("AUTOTEMP"):
2364            autotemp = self._parse_schema()
2365
2366        return self.expression(
2367            exp.BlockCompressionProperty,
2368            always=always,
2369            manual=manual,
2370            never=never,
2371            default=default,
2372            autotemp=autotemp,
2373        )
2374
2375    def _parse_withisolatedloading(self) -> t.Optional[exp.IsolatedLoadingProperty]:
2376        index = self._index
2377        no = self._match_text_seq("NO")
2378        concurrent = self._match_text_seq("CONCURRENT")
2379
2380        if not self._match_text_seq("ISOLATED", "LOADING"):
2381            self._retreat(index)
2382            return None
2383
2384        target = self._parse_var_from_options(self.ISOLATED_LOADING_OPTIONS, raise_unmatched=False)
2385        return self.expression(
2386            exp.IsolatedLoadingProperty, no=no, concurrent=concurrent, target=target
2387        )
2388
2389    def _parse_locking(self) -> exp.LockingProperty:
2390        if self._match(TokenType.TABLE):
2391            kind = "TABLE"
2392        elif self._match(TokenType.VIEW):
2393            kind = "VIEW"
2394        elif self._match(TokenType.ROW):
2395            kind = "ROW"
2396        elif self._match_text_seq("DATABASE"):
2397            kind = "DATABASE"
2398        else:
2399            kind = None
2400
2401        if kind in ("DATABASE", "TABLE", "VIEW"):
2402            this = self._parse_table_parts()
2403        else:
2404            this = None
2405
2406        if self._match(TokenType.FOR):
2407            for_or_in = "FOR"
2408        elif self._match(TokenType.IN):
2409            for_or_in = "IN"
2410        else:
2411            for_or_in = None
2412
2413        if self._match_text_seq("ACCESS"):
2414            lock_type = "ACCESS"
2415        elif self._match_texts(("EXCL", "EXCLUSIVE")):
2416            lock_type = "EXCLUSIVE"
2417        elif self._match_text_seq("SHARE"):
2418            lock_type = "SHARE"
2419        elif self._match_text_seq("READ"):
2420            lock_type = "READ"
2421        elif self._match_text_seq("WRITE"):
2422            lock_type = "WRITE"
2423        elif self._match_text_seq("CHECKSUM"):
2424            lock_type = "CHECKSUM"
2425        else:
2426            lock_type = None
2427
2428        override = self._match_text_seq("OVERRIDE")
2429
2430        return self.expression(
2431            exp.LockingProperty,
2432            this=this,
2433            kind=kind,
2434            for_or_in=for_or_in,
2435            lock_type=lock_type,
2436            override=override,
2437        )
2438
2439    def _parse_partition_by(self) -> t.List[exp.Expression]:
2440        if self._match(TokenType.PARTITION_BY):
2441            return self._parse_csv(self._parse_assignment)
2442        return []
2443
2444    def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
2445        def _parse_partition_bound_expr() -> t.Optional[exp.Expression]:
2446            if self._match_text_seq("MINVALUE"):
2447                return exp.var("MINVALUE")
2448            if self._match_text_seq("MAXVALUE"):
2449                return exp.var("MAXVALUE")
2450            return self._parse_bitwise()
2451
2452        this: t.Optional[exp.Expression | t.List[exp.Expression]] = None
2453        expression = None
2454        from_expressions = None
2455        to_expressions = None
2456
2457        if self._match(TokenType.IN):
2458            this = self._parse_wrapped_csv(self._parse_bitwise)
2459        elif self._match(TokenType.FROM):
2460            from_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
2461            self._match_text_seq("TO")
2462            to_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
2463        elif self._match_text_seq("WITH", "(", "MODULUS"):
2464            this = self._parse_number()
2465            self._match_text_seq(",", "REMAINDER")
2466            expression = self._parse_number()
2467            self._match_r_paren()
2468        else:
2469            self.raise_error("Failed to parse partition bound spec.")
2470
2471        return self.expression(
2472            exp.PartitionBoundSpec,
2473            this=this,
2474            expression=expression,
2475            from_expressions=from_expressions,
2476            to_expressions=to_expressions,
2477        )
2478
2479    # https://www.postgresql.org/docs/current/sql-createtable.html
2480    def _parse_partitioned_of(self) -> t.Optional[exp.PartitionedOfProperty]:
2481        if not self._match_text_seq("OF"):
2482            self._retreat(self._index - 1)
2483            return None
2484
2485        this = self._parse_table(schema=True)
2486
2487        if self._match(TokenType.DEFAULT):
2488            expression: exp.Var | exp.PartitionBoundSpec = exp.var("DEFAULT")
2489        elif self._match_text_seq("FOR", "VALUES"):
2490            expression = self._parse_partition_bound_spec()
2491        else:
2492            self.raise_error("Expecting either DEFAULT or FOR VALUES clause.")
2493
2494        return self.expression(exp.PartitionedOfProperty, this=this, expression=expression)
2495
2496    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
2497        self._match(TokenType.EQ)
2498        return self.expression(
2499            exp.PartitionedByProperty,
2500            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
2501        )
2502
2503    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
2504        if self._match_text_seq("AND", "STATISTICS"):
2505            statistics = True
2506        elif self._match_text_seq("AND", "NO", "STATISTICS"):
2507            statistics = False
2508        else:
2509            statistics = None
2510
2511        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
2512
2513    def _parse_contains_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2514        if self._match_text_seq("SQL"):
2515            return self.expression(exp.SqlReadWriteProperty, this="CONTAINS SQL")
2516        return None
2517
2518    def _parse_modifies_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2519        if self._match_text_seq("SQL", "DATA"):
2520            return self.expression(exp.SqlReadWriteProperty, this="MODIFIES SQL DATA")
2521        return None
2522
2523    def _parse_no_property(self) -> t.Optional[exp.Expression]:
2524        if self._match_text_seq("PRIMARY", "INDEX"):
2525            return exp.NoPrimaryIndexProperty()
2526        if self._match_text_seq("SQL"):
2527            return self.expression(exp.SqlReadWriteProperty, this="NO SQL")
2528        return None
2529
2530    def _parse_on_property(self) -> t.Optional[exp.Expression]:
2531        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
2532            return exp.OnCommitProperty()
2533        if self._match_text_seq("COMMIT", "DELETE", "ROWS"):
2534            return exp.OnCommitProperty(delete=True)
2535        return self.expression(exp.OnProperty, this=self._parse_schema(self._parse_id_var()))
2536
2537    def _parse_reads_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2538        if self._match_text_seq("SQL", "DATA"):
2539            return self.expression(exp.SqlReadWriteProperty, this="READS SQL DATA")
2540        return None
2541
2542    def _parse_distkey(self) -> exp.DistKeyProperty:
2543        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
2544
2545    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
2546        table = self._parse_table(schema=True)
2547
2548        options = []
2549        while self._match_texts(("INCLUDING", "EXCLUDING")):
2550            this = self._prev.text.upper()
2551
2552            id_var = self._parse_id_var()
2553            if not id_var:
2554                return None
2555
2556            options.append(
2557                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
2558            )
2559
2560        return self.expression(exp.LikeProperty, this=table, expressions=options)
2561
2562    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
2563        return self.expression(
2564            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
2565        )
2566
2567    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
2568        self._match(TokenType.EQ)
2569        return self.expression(
2570            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
2571        )
2572
2573    def _parse_remote_with_connection(self) -> exp.RemoteWithConnectionModelProperty:
2574        self._match_text_seq("WITH", "CONNECTION")
2575        return self.expression(
2576            exp.RemoteWithConnectionModelProperty, this=self._parse_table_parts()
2577        )
2578
2579    def _parse_returns(self) -> exp.ReturnsProperty:
2580        value: t.Optional[exp.Expression]
2581        null = None
2582        is_table = self._match(TokenType.TABLE)
2583
2584        if is_table:
2585            if self._match(TokenType.LT):
2586                value = self.expression(
2587                    exp.Schema,
2588                    this="TABLE",
2589                    expressions=self._parse_csv(self._parse_struct_types),
2590                )
2591                if not self._match(TokenType.GT):
2592                    self.raise_error("Expecting >")
2593            else:
2594                value = self._parse_schema(exp.var("TABLE"))
2595        elif self._match_text_seq("NULL", "ON", "NULL", "INPUT"):
2596            null = True
2597            value = None
2598        else:
2599            value = self._parse_types()
2600
2601        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table, null=null)
2602
2603    def _parse_describe(self) -> exp.Describe:
2604        kind = self._match_set(self.CREATABLES) and self._prev.text
2605        style = self._match_texts(self.DESCRIBE_STYLES) and self._prev.text.upper()
2606        if self._match(TokenType.DOT):
2607            style = None
2608            self._retreat(self._index - 2)
2609        this = self._parse_table(schema=True)
2610        properties = self._parse_properties()
2611        expressions = properties.expressions if properties else None
2612        partition = self._parse_partition()
2613        return self.expression(
2614            exp.Describe,
2615            this=this,
2616            style=style,
2617            kind=kind,
2618            expressions=expressions,
2619            partition=partition,
2620        )
2621
2622    def _parse_multitable_inserts(self, comments: t.Optional[t.List[str]]) -> exp.MultitableInserts:
2623        kind = self._prev.text.upper()
2624        expressions = []
2625
2626        def parse_conditional_insert() -> t.Optional[exp.ConditionalInsert]:
2627            if self._match(TokenType.WHEN):
2628                expression = self._parse_disjunction()
2629                self._match(TokenType.THEN)
2630            else:
2631                expression = None
2632
2633            else_ = self._match(TokenType.ELSE)
2634
2635            if not self._match(TokenType.INTO):
2636                return None
2637
2638            return self.expression(
2639                exp.ConditionalInsert,
2640                this=self.expression(
2641                    exp.Insert,
2642                    this=self._parse_table(schema=True),
2643                    expression=self._parse_derived_table_values(),
2644                ),
2645                expression=expression,
2646                else_=else_,
2647            )
2648
2649        expression = parse_conditional_insert()
2650        while expression is not None:
2651            expressions.append(expression)
2652            expression = parse_conditional_insert()
2653
2654        return self.expression(
2655            exp.MultitableInserts,
2656            kind=kind,
2657            comments=comments,
2658            expressions=expressions,
2659            source=self._parse_table(),
2660        )
2661
2662    def _parse_insert(self) -> t.Union[exp.Insert, exp.MultitableInserts]:
2663        comments = ensure_list(self._prev_comments)
2664        hint = self._parse_hint()
2665        overwrite = self._match(TokenType.OVERWRITE)
2666        ignore = self._match(TokenType.IGNORE)
2667        local = self._match_text_seq("LOCAL")
2668        alternative = None
2669        is_function = None
2670
2671        if self._match_text_seq("DIRECTORY"):
2672            this: t.Optional[exp.Expression] = self.expression(
2673                exp.Directory,
2674                this=self._parse_var_or_string(),
2675                local=local,
2676                row_format=self._parse_row_format(match_row=True),
2677            )
2678        else:
2679            if self._match_set((TokenType.FIRST, TokenType.ALL)):
2680                comments += ensure_list(self._prev_comments)
2681                return self._parse_multitable_inserts(comments)
2682
2683            if self._match(TokenType.OR):
2684                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
2685
2686            self._match(TokenType.INTO)
2687            comments += ensure_list(self._prev_comments)
2688            self._match(TokenType.TABLE)
2689            is_function = self._match(TokenType.FUNCTION)
2690
2691            this = (
2692                self._parse_table(schema=True, parse_partition=True)
2693                if not is_function
2694                else self._parse_function()
2695            )
2696
2697        returning = self._parse_returning()
2698
2699        return self.expression(
2700            exp.Insert,
2701            comments=comments,
2702            hint=hint,
2703            is_function=is_function,
2704            this=this,
2705            stored=self._match_text_seq("STORED") and self._parse_stored(),
2706            by_name=self._match_text_seq("BY", "NAME"),
2707            exists=self._parse_exists(),
2708            where=self._match_pair(TokenType.REPLACE, TokenType.WHERE) and self._parse_assignment(),
2709            partition=self._match(TokenType.PARTITION_BY) and self._parse_partitioned_by(),
2710            settings=self._match_text_seq("SETTINGS") and self._parse_settings_property(),
2711            expression=self._parse_derived_table_values() or self._parse_ddl_select(),
2712            conflict=self._parse_on_conflict(),
2713            returning=returning or self._parse_returning(),
2714            overwrite=overwrite,
2715            alternative=alternative,
2716            ignore=ignore,
2717            source=self._match(TokenType.TABLE) and self._parse_table(),
2718        )
2719
2720    def _parse_kill(self) -> exp.Kill:
2721        kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
2722
2723        return self.expression(
2724            exp.Kill,
2725            this=self._parse_primary(),
2726            kind=kind,
2727        )
2728
2729    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
2730        conflict = self._match_text_seq("ON", "CONFLICT")
2731        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
2732
2733        if not conflict and not duplicate:
2734            return None
2735
2736        conflict_keys = None
2737        constraint = None
2738
2739        if conflict:
2740            if self._match_text_seq("ON", "CONSTRAINT"):
2741                constraint = self._parse_id_var()
2742            elif self._match(TokenType.L_PAREN):
2743                conflict_keys = self._parse_csv(self._parse_id_var)
2744                self._match_r_paren()
2745
2746        action = self._parse_var_from_options(self.CONFLICT_ACTIONS)
2747        if self._prev.token_type == TokenType.UPDATE:
2748            self._match(TokenType.SET)
2749            expressions = self._parse_csv(self._parse_equality)
2750        else:
2751            expressions = None
2752
2753        return self.expression(
2754            exp.OnConflict,
2755            duplicate=duplicate,
2756            expressions=expressions,
2757            action=action,
2758            conflict_keys=conflict_keys,
2759            constraint=constraint,
2760        )
2761
2762    def _parse_returning(self) -> t.Optional[exp.Returning]:
2763        if not self._match(TokenType.RETURNING):
2764            return None
2765        return self.expression(
2766            exp.Returning,
2767            expressions=self._parse_csv(self._parse_expression),
2768            into=self._match(TokenType.INTO) and self._parse_table_part(),
2769        )
2770
2771    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2772        if not self._match(TokenType.FORMAT):
2773            return None
2774        return self._parse_row_format()
2775
2776    def _parse_serde_properties(self, with_: bool = False) -> t.Optional[exp.SerdeProperties]:
2777        index = self._index
2778        with_ = with_ or self._match_text_seq("WITH")
2779
2780        if not self._match(TokenType.SERDE_PROPERTIES):
2781            self._retreat(index)
2782            return None
2783        return self.expression(
2784            exp.SerdeProperties,
2785            **{  # type: ignore
2786                "expressions": self._parse_wrapped_properties(),
2787                "with": with_,
2788            },
2789        )
2790
2791    def _parse_row_format(
2792        self, match_row: bool = False
2793    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2794        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
2795            return None
2796
2797        if self._match_text_seq("SERDE"):
2798            this = self._parse_string()
2799
2800            serde_properties = self._parse_serde_properties()
2801
2802            return self.expression(
2803                exp.RowFormatSerdeProperty, this=this, serde_properties=serde_properties
2804            )
2805
2806        self._match_text_seq("DELIMITED")
2807
2808        kwargs = {}
2809
2810        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
2811            kwargs["fields"] = self._parse_string()
2812            if self._match_text_seq("ESCAPED", "BY"):
2813                kwargs["escaped"] = self._parse_string()
2814        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
2815            kwargs["collection_items"] = self._parse_string()
2816        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
2817            kwargs["map_keys"] = self._parse_string()
2818        if self._match_text_seq("LINES", "TERMINATED", "BY"):
2819            kwargs["lines"] = self._parse_string()
2820        if self._match_text_seq("NULL", "DEFINED", "AS"):
2821            kwargs["null"] = self._parse_string()
2822
2823        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
2824
2825    def _parse_load(self) -> exp.LoadData | exp.Command:
2826        if self._match_text_seq("DATA"):
2827            local = self._match_text_seq("LOCAL")
2828            self._match_text_seq("INPATH")
2829            inpath = self._parse_string()
2830            overwrite = self._match(TokenType.OVERWRITE)
2831            self._match_pair(TokenType.INTO, TokenType.TABLE)
2832
2833            return self.expression(
2834                exp.LoadData,
2835                this=self._parse_table(schema=True),
2836                local=local,
2837                overwrite=overwrite,
2838                inpath=inpath,
2839                partition=self._parse_partition(),
2840                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
2841                serde=self._match_text_seq("SERDE") and self._parse_string(),
2842            )
2843        return self._parse_as_command(self._prev)
2844
2845    def _parse_delete(self) -> exp.Delete:
2846        # This handles MySQL's "Multiple-Table Syntax"
2847        # https://dev.mysql.com/doc/refman/8.0/en/delete.html
2848        tables = None
2849        comments = self._prev_comments
2850        if not self._match(TokenType.FROM, advance=False):
2851            tables = self._parse_csv(self._parse_table) or None
2852
2853        returning = self._parse_returning()
2854
2855        return self.expression(
2856            exp.Delete,
2857            comments=comments,
2858            tables=tables,
2859            this=self._match(TokenType.FROM) and self._parse_table(joins=True),
2860            using=self._match(TokenType.USING) and self._parse_table(joins=True),
2861            cluster=self._match(TokenType.ON) and self._parse_on_property(),
2862            where=self._parse_where(),
2863            returning=returning or self._parse_returning(),
2864            limit=self._parse_limit(),
2865        )
2866
2867    def _parse_update(self) -> exp.Update:
2868        comments = self._prev_comments
2869        this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
2870        expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
2871        returning = self._parse_returning()
2872        return self.expression(
2873            exp.Update,
2874            comments=comments,
2875            **{  # type: ignore
2876                "this": this,
2877                "expressions": expressions,
2878                "from": self._parse_from(joins=True),
2879                "where": self._parse_where(),
2880                "returning": returning or self._parse_returning(),
2881                "order": self._parse_order(),
2882                "limit": self._parse_limit(),
2883            },
2884        )
2885
2886    def _parse_uncache(self) -> exp.Uncache:
2887        if not self._match(TokenType.TABLE):
2888            self.raise_error("Expecting TABLE after UNCACHE")
2889
2890        return self.expression(
2891            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
2892        )
2893
2894    def _parse_cache(self) -> exp.Cache:
2895        lazy = self._match_text_seq("LAZY")
2896        self._match(TokenType.TABLE)
2897        table = self._parse_table(schema=True)
2898
2899        options = []
2900        if self._match_text_seq("OPTIONS"):
2901            self._match_l_paren()
2902            k = self._parse_string()
2903            self._match(TokenType.EQ)
2904            v = self._parse_string()
2905            options = [k, v]
2906            self._match_r_paren()
2907
2908        self._match(TokenType.ALIAS)
2909        return self.expression(
2910            exp.Cache,
2911            this=table,
2912            lazy=lazy,
2913            options=options,
2914            expression=self._parse_select(nested=True),
2915        )
2916
2917    def _parse_partition(self) -> t.Optional[exp.Partition]:
2918        if not self._match(TokenType.PARTITION):
2919            return None
2920
2921        return self.expression(
2922            exp.Partition, expressions=self._parse_wrapped_csv(self._parse_assignment)
2923        )
2924
2925    def _parse_value(self) -> t.Optional[exp.Tuple]:
2926        if self._match(TokenType.L_PAREN):
2927            expressions = self._parse_csv(self._parse_expression)
2928            self._match_r_paren()
2929            return self.expression(exp.Tuple, expressions=expressions)
2930
2931        # In some dialects we can have VALUES 1, 2 which results in 1 column & 2 rows.
2932        expression = self._parse_expression()
2933        if expression:
2934            return self.expression(exp.Tuple, expressions=[expression])
2935        return None
2936
2937    def _parse_projections(self) -> t.List[exp.Expression]:
2938        return self._parse_expressions()
2939
2940    def _parse_select(
2941        self,
2942        nested: bool = False,
2943        table: bool = False,
2944        parse_subquery_alias: bool = True,
2945        parse_set_operation: bool = True,
2946    ) -> t.Optional[exp.Expression]:
2947        cte = self._parse_with()
2948
2949        if cte:
2950            this = self._parse_statement()
2951
2952            if not this:
2953                self.raise_error("Failed to parse any statement following CTE")
2954                return cte
2955
2956            if "with" in this.arg_types:
2957                this.set("with", cte)
2958            else:
2959                self.raise_error(f"{this.key} does not support CTE")
2960                this = cte
2961
2962            return this
2963
2964        # duckdb supports leading with FROM x
2965        from_ = self._parse_from() if self._match(TokenType.FROM, advance=False) else None
2966
2967        if self._match(TokenType.SELECT):
2968            comments = self._prev_comments
2969
2970            hint = self._parse_hint()
2971
2972            if self._next and not self._next.token_type == TokenType.DOT:
2973                all_ = self._match(TokenType.ALL)
2974                distinct = self._match_set(self.DISTINCT_TOKENS)
2975            else:
2976                all_, distinct = None, None
2977
2978            kind = (
2979                self._match(TokenType.ALIAS)
2980                and self._match_texts(("STRUCT", "VALUE"))
2981                and self._prev.text.upper()
2982            )
2983
2984            if distinct:
2985                distinct = self.expression(
2986                    exp.Distinct,
2987                    on=self._parse_value() if self._match(TokenType.ON) else None,
2988                )
2989
2990            if all_ and distinct:
2991                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
2992
2993            operation_modifiers = []
2994            while self._curr and self._match_texts(self.OPERATION_MODIFIERS):
2995                operation_modifiers.append(exp.var(self._prev.text.upper()))
2996
2997            limit = self._parse_limit(top=True)
2998            projections = self._parse_projections()
2999
3000            this = self.expression(
3001                exp.Select,
3002                kind=kind,
3003                hint=hint,
3004                distinct=distinct,
3005                expressions=projections,
3006                limit=limit,
3007                operation_modifiers=operation_modifiers or None,
3008            )
3009            this.comments = comments
3010
3011            into = self._parse_into()
3012            if into:
3013                this.set("into", into)
3014
3015            if not from_:
3016                from_ = self._parse_from()
3017
3018            if from_:
3019                this.set("from", from_)
3020
3021            this = self._parse_query_modifiers(this)
3022        elif (table or nested) and self._match(TokenType.L_PAREN):
3023            if self._match(TokenType.PIVOT):
3024                this = self._parse_simplified_pivot()
3025            elif self._match(TokenType.FROM):
3026                this = exp.select("*").from_(
3027                    t.cast(exp.From, self._parse_from(skip_from_token=True))
3028                )
3029            else:
3030                this = (
3031                    self._parse_table()
3032                    if table
3033                    else self._parse_select(nested=True, parse_set_operation=False)
3034                )
3035
3036                # Transform exp.Values into a exp.Table to pass through parse_query_modifiers
3037                # in case a modifier (e.g. join) is following
3038                if table and isinstance(this, exp.Values) and this.alias:
3039                    alias = this.args["alias"].pop()
3040                    this = exp.Table(this=this, alias=alias)
3041
3042                this = self._parse_query_modifiers(self._parse_set_operations(this))
3043
3044            self._match_r_paren()
3045
3046            # We return early here so that the UNION isn't attached to the subquery by the
3047            # following call to _parse_set_operations, but instead becomes the parent node
3048            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
3049        elif self._match(TokenType.VALUES, advance=False):
3050            this = self._parse_derived_table_values()
3051        elif from_:
3052            this = exp.select("*").from_(from_.this, copy=False)
3053        elif self._match(TokenType.SUMMARIZE):
3054            table = self._match(TokenType.TABLE)
3055            this = self._parse_select() or self._parse_string() or self._parse_table()
3056            return self.expression(exp.Summarize, this=this, table=table)
3057        elif self._match(TokenType.DESCRIBE):
3058            this = self._parse_describe()
3059        elif self._match_text_seq("STREAM"):
3060            this = self._parse_function()
3061            if this:
3062                this = self.expression(exp.Stream, this=this)
3063            else:
3064                self._retreat(self._index - 1)
3065        else:
3066            this = None
3067
3068        return self._parse_set_operations(this) if parse_set_operation else this
3069
3070    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
3071        if not skip_with_token and not self._match(TokenType.WITH):
3072            return None
3073
3074        comments = self._prev_comments
3075        recursive = self._match(TokenType.RECURSIVE)
3076
3077        last_comments = None
3078        expressions = []
3079        while True:
3080            expressions.append(self._parse_cte())
3081            if last_comments:
3082                expressions[-1].add_comments(last_comments)
3083
3084            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
3085                break
3086            else:
3087                self._match(TokenType.WITH)
3088
3089            last_comments = self._prev_comments
3090
3091        return self.expression(
3092            exp.With, comments=comments, expressions=expressions, recursive=recursive
3093        )
3094
3095    def _parse_cte(self) -> exp.CTE:
3096        alias = self._parse_table_alias(self.ID_VAR_TOKENS)
3097        if not alias or not alias.this:
3098            self.raise_error("Expected CTE to have alias")
3099
3100        self._match(TokenType.ALIAS)
3101        comments = self._prev_comments
3102
3103        if self._match_text_seq("NOT", "MATERIALIZED"):
3104            materialized = False
3105        elif self._match_text_seq("MATERIALIZED"):
3106            materialized = True
3107        else:
3108            materialized = None
3109
3110        return self.expression(
3111            exp.CTE,
3112            this=self._parse_wrapped(self._parse_statement),
3113            alias=alias,
3114            materialized=materialized,
3115            comments=comments,
3116        )
3117
3118    def _parse_table_alias(
3119        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
3120    ) -> t.Optional[exp.TableAlias]:
3121        any_token = self._match(TokenType.ALIAS)
3122        alias = (
3123            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
3124            or self._parse_string_as_identifier()
3125        )
3126
3127        index = self._index
3128        if self._match(TokenType.L_PAREN):
3129            columns = self._parse_csv(self._parse_function_parameter)
3130            self._match_r_paren() if columns else self._retreat(index)
3131        else:
3132            columns = None
3133
3134        if not alias and not columns:
3135            return None
3136
3137        table_alias = self.expression(exp.TableAlias, this=alias, columns=columns)
3138
3139        # We bubble up comments from the Identifier to the TableAlias
3140        if isinstance(alias, exp.Identifier):
3141            table_alias.add_comments(alias.pop_comments())
3142
3143        return table_alias
3144
3145    def _parse_subquery(
3146        self, this: t.Optional[exp.Expression], parse_alias: bool = True
3147    ) -> t.Optional[exp.Subquery]:
3148        if not this:
3149            return None
3150
3151        return self.expression(
3152            exp.Subquery,
3153            this=this,
3154            pivots=self._parse_pivots(),
3155            alias=self._parse_table_alias() if parse_alias else None,
3156            sample=self._parse_table_sample(),
3157        )
3158
3159    def _implicit_unnests_to_explicit(self, this: E) -> E:
3160        from sqlglot.optimizer.normalize_identifiers import normalize_identifiers as _norm
3161
3162        refs = {_norm(this.args["from"].this.copy(), dialect=self.dialect).alias_or_name}
3163        for i, join in enumerate(this.args.get("joins") or []):
3164            table = join.this
3165            normalized_table = table.copy()
3166            normalized_table.meta["maybe_column"] = True
3167            normalized_table = _norm(normalized_table, dialect=self.dialect)
3168
3169            if isinstance(table, exp.Table) and not join.args.get("on"):
3170                if normalized_table.parts[0].name in refs:
3171                    table_as_column = table.to_column()
3172                    unnest = exp.Unnest(expressions=[table_as_column])
3173
3174                    # Table.to_column creates a parent Alias node that we want to convert to
3175                    # a TableAlias and attach to the Unnest, so it matches the parser's output
3176                    if isinstance(table.args.get("alias"), exp.TableAlias):
3177                        table_as_column.replace(table_as_column.this)
3178                        exp.alias_(unnest, None, table=[table.args["alias"].this], copy=False)
3179
3180                    table.replace(unnest)
3181
3182            refs.add(normalized_table.alias_or_name)
3183
3184        return this
3185
3186    def _parse_query_modifiers(
3187        self, this: t.Optional[exp.Expression]
3188    ) -> t.Optional[exp.Expression]:
3189        if isinstance(this, (exp.Query, exp.Table)):
3190            for join in self._parse_joins():
3191                this.append("joins", join)
3192            for lateral in iter(self._parse_lateral, None):
3193                this.append("laterals", lateral)
3194
3195            while True:
3196                if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
3197                    parser = self.QUERY_MODIFIER_PARSERS[self._curr.token_type]
3198                    key, expression = parser(self)
3199
3200                    if expression:
3201                        this.set(key, expression)
3202                        if key == "limit":
3203                            offset = expression.args.pop("offset", None)
3204
3205                            if offset:
3206                                offset = exp.Offset(expression=offset)
3207                                this.set("offset", offset)
3208
3209                                limit_by_expressions = expression.expressions
3210                                expression.set("expressions", None)
3211                                offset.set("expressions", limit_by_expressions)
3212                        continue
3213                break
3214
3215        if self.SUPPORTS_IMPLICIT_UNNEST and this and this.args.get("from"):
3216            this = self._implicit_unnests_to_explicit(this)
3217
3218        return this
3219
3220    def _parse_hint(self) -> t.Optional[exp.Hint]:
3221        if self._match(TokenType.HINT):
3222            hints = []
3223            for hint in iter(
3224                lambda: self._parse_csv(
3225                    lambda: self._parse_function() or self._parse_var(upper=True)
3226                ),
3227                [],
3228            ):
3229                hints.extend(hint)
3230
3231            if not self._match_pair(TokenType.STAR, TokenType.SLASH):
3232                self.raise_error("Expected */ after HINT")
3233
3234            return self.expression(exp.Hint, expressions=hints)
3235
3236        return None
3237
3238    def _parse_into(self) -> t.Optional[exp.Into]:
3239        if not self._match(TokenType.INTO):
3240            return None
3241
3242        temp = self._match(TokenType.TEMPORARY)
3243        unlogged = self._match_text_seq("UNLOGGED")
3244        self._match(TokenType.TABLE)
3245
3246        return self.expression(
3247            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
3248        )
3249
3250    def _parse_from(
3251        self, joins: bool = False, skip_from_token: bool = False
3252    ) -> t.Optional[exp.From]:
3253        if not skip_from_token and not self._match(TokenType.FROM):
3254            return None
3255
3256        return self.expression(
3257            exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
3258        )
3259
3260    def _parse_match_recognize_measure(self) -> exp.MatchRecognizeMeasure:
3261        return self.expression(
3262            exp.MatchRecognizeMeasure,
3263            window_frame=self._match_texts(("FINAL", "RUNNING")) and self._prev.text.upper(),
3264            this=self._parse_expression(),
3265        )
3266
3267    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
3268        if not self._match(TokenType.MATCH_RECOGNIZE):
3269            return None
3270
3271        self._match_l_paren()
3272
3273        partition = self._parse_partition_by()
3274        order = self._parse_order()
3275
3276        measures = (
3277            self._parse_csv(self._parse_match_recognize_measure)
3278            if self._match_text_seq("MEASURES")
3279            else None
3280        )
3281
3282        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
3283            rows = exp.var("ONE ROW PER MATCH")
3284        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
3285            text = "ALL ROWS PER MATCH"
3286            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
3287                text += " SHOW EMPTY MATCHES"
3288            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
3289                text += " OMIT EMPTY MATCHES"
3290            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
3291                text += " WITH UNMATCHED ROWS"
3292            rows = exp.var(text)
3293        else:
3294            rows = None
3295
3296        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
3297            text = "AFTER MATCH SKIP"
3298            if self._match_text_seq("PAST", "LAST", "ROW"):
3299                text += " PAST LAST ROW"
3300            elif self._match_text_seq("TO", "NEXT", "ROW"):
3301                text += " TO NEXT ROW"
3302            elif self._match_text_seq("TO", "FIRST"):
3303                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
3304            elif self._match_text_seq("TO", "LAST"):
3305                text += f" TO LAST {self._advance_any().text}"  # type: ignore
3306            after = exp.var(text)
3307        else:
3308            after = None
3309
3310        if self._match_text_seq("PATTERN"):
3311            self._match_l_paren()
3312
3313            if not self._curr:
3314                self.raise_error("Expecting )", self._curr)
3315
3316            paren = 1
3317            start = self._curr
3318
3319            while self._curr and paren > 0:
3320                if self._curr.token_type == TokenType.L_PAREN:
3321                    paren += 1
3322                if self._curr.token_type == TokenType.R_PAREN:
3323                    paren -= 1
3324
3325                end = self._prev
3326                self._advance()
3327
3328            if paren > 0:
3329                self.raise_error("Expecting )", self._curr)
3330
3331            pattern = exp.var(self._find_sql(start, end))
3332        else:
3333            pattern = None
3334
3335        define = (
3336            self._parse_csv(self._parse_name_as_expression)
3337            if self._match_text_seq("DEFINE")
3338            else None
3339        )
3340
3341        self._match_r_paren()
3342
3343        return self.expression(
3344            exp.MatchRecognize,
3345            partition_by=partition,
3346            order=order,
3347            measures=measures,
3348            rows=rows,
3349            after=after,
3350            pattern=pattern,
3351            define=define,
3352            alias=self._parse_table_alias(),
3353        )
3354
3355    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
3356        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
3357        if not cross_apply and self._match_pair(TokenType.OUTER, TokenType.APPLY):
3358            cross_apply = False
3359
3360        if cross_apply is not None:
3361            this = self._parse_select(table=True)
3362            view = None
3363            outer = None
3364        elif self._match(TokenType.LATERAL):
3365            this = self._parse_select(table=True)
3366            view = self._match(TokenType.VIEW)
3367            outer = self._match(TokenType.OUTER)
3368        else:
3369            return None
3370
3371        if not this:
3372            this = (
3373                self._parse_unnest()
3374                or self._parse_function()
3375                or self._parse_id_var(any_token=False)
3376            )
3377
3378            while self._match(TokenType.DOT):
3379                this = exp.Dot(
3380                    this=this,
3381                    expression=self._parse_function() or self._parse_id_var(any_token=False),
3382                )
3383
3384        if view:
3385            table = self._parse_id_var(any_token=False)
3386            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
3387            table_alias: t.Optional[exp.TableAlias] = self.expression(
3388                exp.TableAlias, this=table, columns=columns
3389            )
3390        elif isinstance(this, (exp.Subquery, exp.Unnest)) and this.alias:
3391            # We move the alias from the lateral's child node to the lateral itself
3392            table_alias = this.args["alias"].pop()
3393        else:
3394            table_alias = self._parse_table_alias()
3395
3396        return self.expression(
3397            exp.Lateral,
3398            this=this,
3399            view=view,
3400            outer=outer,
3401            alias=table_alias,
3402            cross_apply=cross_apply,
3403        )
3404
3405    def _parse_join_parts(
3406        self,
3407    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
3408        return (
3409            self._match_set(self.JOIN_METHODS) and self._prev,
3410            self._match_set(self.JOIN_SIDES) and self._prev,
3411            self._match_set(self.JOIN_KINDS) and self._prev,
3412        )
3413
3414    def _parse_using_identifiers(self) -> t.List[exp.Expression]:
3415        def _parse_column_as_identifier() -> t.Optional[exp.Expression]:
3416            this = self._parse_column()
3417            if isinstance(this, exp.Column):
3418                return this.this
3419            return this
3420
3421        return self._parse_wrapped_csv(_parse_column_as_identifier, optional=True)
3422
3423    def _parse_join(
3424        self, skip_join_token: bool = False, parse_bracket: bool = False
3425    ) -> t.Optional[exp.Join]:
3426        if self._match(TokenType.COMMA):
3427            return self.expression(exp.Join, this=self._parse_table())
3428
3429        index = self._index
3430        method, side, kind = self._parse_join_parts()
3431        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
3432        join = self._match(TokenType.JOIN) or (kind and kind.token_type == TokenType.STRAIGHT_JOIN)
3433
3434        if not skip_join_token and not join:
3435            self._retreat(index)
3436            kind = None
3437            method = None
3438            side = None
3439
3440        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
3441        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
3442
3443        if not skip_join_token and not join and not outer_apply and not cross_apply:
3444            return None
3445
3446        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table(parse_bracket=parse_bracket)}
3447        if kind and kind.token_type == TokenType.ARRAY and self._match(TokenType.COMMA):
3448            kwargs["expressions"] = self._parse_csv(
3449                lambda: self._parse_table(parse_bracket=parse_bracket)
3450            )
3451
3452        if method:
3453            kwargs["method"] = method.text
3454        if side:
3455            kwargs["side"] = side.text
3456        if kind:
3457            kwargs["kind"] = kind.text
3458        if hint:
3459            kwargs["hint"] = hint
3460
3461        if self._match(TokenType.MATCH_CONDITION):
3462            kwargs["match_condition"] = self._parse_wrapped(self._parse_comparison)
3463
3464        if self._match(TokenType.ON):
3465            kwargs["on"] = self._parse_assignment()
3466        elif self._match(TokenType.USING):
3467            kwargs["using"] = self._parse_using_identifiers()
3468        elif (
3469            not (outer_apply or cross_apply)
3470            and not isinstance(kwargs["this"], exp.Unnest)
3471            and not (kind and kind.token_type in (TokenType.CROSS, TokenType.ARRAY))
3472        ):
3473            index = self._index
3474            joins: t.Optional[list] = list(self._parse_joins())
3475
3476            if joins and self._match(TokenType.ON):
3477                kwargs["on"] = self._parse_assignment()
3478            elif joins and self._match(TokenType.USING):
3479                kwargs["using"] = self._parse_using_identifiers()
3480            else:
3481                joins = None
3482                self._retreat(index)
3483
3484            kwargs["this"].set("joins", joins if joins else None)
3485
3486        comments = [c for token in (method, side, kind) if token for c in token.comments]
3487        return self.expression(exp.Join, comments=comments, **kwargs)
3488
3489    def _parse_opclass(self) -> t.Optional[exp.Expression]:
3490        this = self._parse_assignment()
3491
3492        if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
3493            return this
3494
3495        if not self._match_set(self.OPTYPE_FOLLOW_TOKENS, advance=False):
3496            return self.expression(exp.Opclass, this=this, expression=self._parse_table_parts())
3497
3498        return this
3499
3500    def _parse_index_params(self) -> exp.IndexParameters:
3501        using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
3502
3503        if self._match(TokenType.L_PAREN, advance=False):
3504            columns = self._parse_wrapped_csv(self._parse_with_operator)
3505        else:
3506            columns = None
3507
3508        include = self._parse_wrapped_id_vars() if self._match_text_seq("INCLUDE") else None
3509        partition_by = self._parse_partition_by()
3510        with_storage = self._match(TokenType.WITH) and self._parse_wrapped_properties()
3511        tablespace = (
3512            self._parse_var(any_token=True)
3513            if self._match_text_seq("USING", "INDEX", "TABLESPACE")
3514            else None
3515        )
3516        where = self._parse_where()
3517
3518        on = self._parse_field() if self._match(TokenType.ON) else None
3519
3520        return self.expression(
3521            exp.IndexParameters,
3522            using=using,
3523            columns=columns,
3524            include=include,
3525            partition_by=partition_by,
3526            where=where,
3527            with_storage=with_storage,
3528            tablespace=tablespace,
3529            on=on,
3530        )
3531
3532    def _parse_index(
3533        self, index: t.Optional[exp.Expression] = None, anonymous: bool = False
3534    ) -> t.Optional[exp.Index]:
3535        if index or anonymous:
3536            unique = None
3537            primary = None
3538            amp = None
3539
3540            self._match(TokenType.ON)
3541            self._match(TokenType.TABLE)  # hive
3542            table = self._parse_table_parts(schema=True)
3543        else:
3544            unique = self._match(TokenType.UNIQUE)
3545            primary = self._match_text_seq("PRIMARY")
3546            amp = self._match_text_seq("AMP")
3547
3548            if not self._match(TokenType.INDEX):
3549                return None
3550
3551            index = self._parse_id_var()
3552            table = None
3553
3554        params = self._parse_index_params()
3555
3556        return self.expression(
3557            exp.Index,
3558            this=index,
3559            table=table,
3560            unique=unique,
3561            primary=primary,
3562            amp=amp,
3563            params=params,
3564        )
3565
3566    def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
3567        hints: t.List[exp.Expression] = []
3568        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
3569            # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
3570            hints.append(
3571                self.expression(
3572                    exp.WithTableHint,
3573                    expressions=self._parse_csv(
3574                        lambda: self._parse_function() or self._parse_var(any_token=True)
3575                    ),
3576                )
3577            )
3578            self._match_r_paren()
3579        else:
3580            # https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
3581            while self._match_set(self.TABLE_INDEX_HINT_TOKENS):
3582                hint = exp.IndexTableHint(this=self._prev.text.upper())
3583
3584                self._match_set((TokenType.INDEX, TokenType.KEY))
3585                if self._match(TokenType.FOR):
3586                    hint.set("target", self._advance_any() and self._prev.text.upper())
3587
3588                hint.set("expressions", self._parse_wrapped_id_vars())
3589                hints.append(hint)
3590
3591        return hints or None
3592
3593    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
3594        return (
3595            (not schema and self._parse_function(optional_parens=False))
3596            or self._parse_id_var(any_token=False)
3597            or self._parse_string_as_identifier()
3598            or self._parse_placeholder()
3599        )
3600
3601    def _parse_table_parts(
3602        self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
3603    ) -> exp.Table:
3604        catalog = None
3605        db = None
3606        table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
3607
3608        while self._match(TokenType.DOT):
3609            if catalog:
3610                # This allows nesting the table in arbitrarily many dot expressions if needed
3611                table = self.expression(
3612                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
3613                )
3614            else:
3615                catalog = db
3616                db = table
3617                # "" used for tsql FROM a..b case
3618                table = self._parse_table_part(schema=schema) or ""
3619
3620        if (
3621            wildcard
3622            and self._is_connected()
3623            and (isinstance(table, exp.Identifier) or not table)
3624            and self._match(TokenType.STAR)
3625        ):
3626            if isinstance(table, exp.Identifier):
3627                table.args["this"] += "*"
3628            else:
3629                table = exp.Identifier(this="*")
3630
3631        # We bubble up comments from the Identifier to the Table
3632        comments = table.pop_comments() if isinstance(table, exp.Expression) else None
3633
3634        if is_db_reference:
3635            catalog = db
3636            db = table
3637            table = None
3638
3639        if not table and not is_db_reference:
3640            self.raise_error(f"Expected table name but got {self._curr}")
3641        if not db and is_db_reference:
3642            self.raise_error(f"Expected database name but got {self._curr}")
3643
3644        table = self.expression(
3645            exp.Table,
3646            comments=comments,
3647            this=table,
3648            db=db,
3649            catalog=catalog,
3650        )
3651
3652        changes = self._parse_changes()
3653        if changes:
3654            table.set("changes", changes)
3655
3656        at_before = self._parse_historical_data()
3657        if at_before:
3658            table.set("when", at_before)
3659
3660        pivots = self._parse_pivots()
3661        if pivots:
3662            table.set("pivots", pivots)
3663
3664        return table
3665
3666    def _parse_table(
3667        self,
3668        schema: bool = False,
3669        joins: bool = False,
3670        alias_tokens: t.Optional[t.Collection[TokenType]] = None,
3671        parse_bracket: bool = False,
3672        is_db_reference: bool = False,
3673        parse_partition: bool = False,
3674    ) -> t.Optional[exp.Expression]:
3675        lateral = self._parse_lateral()
3676        if lateral:
3677            return lateral
3678
3679        unnest = self._parse_unnest()
3680        if unnest:
3681            return unnest
3682
3683        values = self._parse_derived_table_values()
3684        if values:
3685            return values
3686
3687        subquery = self._parse_select(table=True)
3688        if subquery:
3689            if not subquery.args.get("pivots"):
3690                subquery.set("pivots", self._parse_pivots())
3691            return subquery
3692
3693        bracket = parse_bracket and self._parse_bracket(None)
3694        bracket = self.expression(exp.Table, this=bracket) if bracket else None
3695
3696        rows_from = self._match_text_seq("ROWS", "FROM") and self._parse_wrapped_csv(
3697            self._parse_table
3698        )
3699        rows_from = self.expression(exp.Table, rows_from=rows_from) if rows_from else None
3700
3701        only = self._match(TokenType.ONLY)
3702
3703        this = t.cast(
3704            exp.Expression,
3705            bracket
3706            or rows_from
3707            or self._parse_bracket(
3708                self._parse_table_parts(schema=schema, is_db_reference=is_db_reference)
3709            ),
3710        )
3711
3712        if only:
3713            this.set("only", only)
3714
3715        # Postgres supports a wildcard (table) suffix operator, which is a no-op in this context
3716        self._match_text_seq("*")
3717
3718        parse_partition = parse_partition or self.SUPPORTS_PARTITION_SELECTION
3719        if parse_partition and self._match(TokenType.PARTITION, advance=False):
3720            this.set("partition", self._parse_partition())
3721
3722        if schema:
3723            return self._parse_schema(this=this)
3724
3725        version = self._parse_version()
3726
3727        if version:
3728            this.set("version", version)
3729
3730        if self.dialect.ALIAS_POST_TABLESAMPLE:
3731            this.set("sample", self._parse_table_sample())
3732
3733        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
3734        if alias:
3735            this.set("alias", alias)
3736
3737        if isinstance(this, exp.Table) and self._match_text_seq("AT"):
3738            return self.expression(
3739                exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
3740            )
3741
3742        this.set("hints", self._parse_table_hints())
3743
3744        if not this.args.get("pivots"):
3745            this.set("pivots", self._parse_pivots())
3746
3747        if not self.dialect.ALIAS_POST_TABLESAMPLE:
3748            this.set("sample", self._parse_table_sample())
3749
3750        if joins:
3751            for join in self._parse_joins():
3752                this.append("joins", join)
3753
3754        if self._match_pair(TokenType.WITH, TokenType.ORDINALITY):
3755            this.set("ordinality", True)
3756            this.set("alias", self._parse_table_alias())
3757
3758        return this
3759
3760    def _parse_version(self) -> t.Optional[exp.Version]:
3761        if self._match(TokenType.TIMESTAMP_SNAPSHOT):
3762            this = "TIMESTAMP"
3763        elif self._match(TokenType.VERSION_SNAPSHOT):
3764            this = "VERSION"
3765        else:
3766            return None
3767
3768        if self._match_set((TokenType.FROM, TokenType.BETWEEN)):
3769            kind = self._prev.text.upper()
3770            start = self._parse_bitwise()
3771            self._match_texts(("TO", "AND"))
3772            end = self._parse_bitwise()
3773            expression: t.Optional[exp.Expression] = self.expression(
3774                exp.Tuple, expressions=[start, end]
3775            )
3776        elif self._match_text_seq("CONTAINED", "IN"):
3777            kind = "CONTAINED IN"
3778            expression = self.expression(
3779                exp.Tuple, expressions=self._parse_wrapped_csv(self._parse_bitwise)
3780            )
3781        elif self._match(TokenType.ALL):
3782            kind = "ALL"
3783            expression = None
3784        else:
3785            self._match_text_seq("AS", "OF")
3786            kind = "AS OF"
3787            expression = self._parse_type()
3788
3789        return self.expression(exp.Version, this=this, expression=expression, kind=kind)
3790
3791    def _parse_historical_data(self) -> t.Optional[exp.HistoricalData]:
3792        # https://docs.snowflake.com/en/sql-reference/constructs/at-before
3793        index = self._index
3794        historical_data = None
3795        if self._match_texts(self.HISTORICAL_DATA_PREFIX):
3796            this = self._prev.text.upper()
3797            kind = (
3798                self._match(TokenType.L_PAREN)
3799                and self._match_texts(self.HISTORICAL_DATA_KIND)
3800                and self._prev.text.upper()
3801            )
3802            expression = self._match(TokenType.FARROW) and self._parse_bitwise()
3803
3804            if expression:
3805                self._match_r_paren()
3806                historical_data = self.expression(
3807                    exp.HistoricalData, this=this, kind=kind, expression=expression
3808                )
3809            else:
3810                self._retreat(index)
3811
3812        return historical_data
3813
3814    def _parse_changes(self) -> t.Optional[exp.Changes]:
3815        if not self._match_text_seq("CHANGES", "(", "INFORMATION", "=>"):
3816            return None
3817
3818        information = self._parse_var(any_token=True)
3819        self._match_r_paren()
3820
3821        return self.expression(
3822            exp.Changes,
3823            information=information,
3824            at_before=self._parse_historical_data(),
3825            end=self._parse_historical_data(),
3826        )
3827
3828    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
3829        if not self._match(TokenType.UNNEST):
3830            return None
3831
3832        expressions = self._parse_wrapped_csv(self._parse_equality)
3833        offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
3834
3835        alias = self._parse_table_alias() if with_alias else None
3836
3837        if alias:
3838            if self.dialect.UNNEST_COLUMN_ONLY:
3839                if alias.args.get("columns"):
3840                    self.raise_error("Unexpected extra column alias in unnest.")
3841
3842                alias.set("columns", [alias.this])
3843                alias.set("this", None)
3844
3845            columns = alias.args.get("columns") or []
3846            if offset and len(expressions) < len(columns):
3847                offset = columns.pop()
3848
3849        if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
3850            self._match(TokenType.ALIAS)
3851            offset = self._parse_id_var(
3852                any_token=False, tokens=self.UNNEST_OFFSET_ALIAS_TOKENS
3853            ) or exp.to_identifier("offset")
3854
3855        return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
3856
3857    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
3858        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
3859        if not is_derived and not (
3860            # ClickHouse's `FORMAT Values` is equivalent to `VALUES`
3861            self._match_text_seq("VALUES") or self._match_text_seq("FORMAT", "VALUES")
3862        ):
3863            return None
3864
3865        expressions = self._parse_csv(self._parse_value)
3866        alias = self._parse_table_alias()
3867
3868        if is_derived:
3869            self._match_r_paren()
3870
3871        return self.expression(
3872            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
3873        )
3874
3875    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
3876        if not self._match(TokenType.TABLE_SAMPLE) and not (
3877            as_modifier and self._match_text_seq("USING", "SAMPLE")
3878        ):
3879            return None
3880
3881        bucket_numerator = None
3882        bucket_denominator = None
3883        bucket_field = None
3884        percent = None
3885        size = None
3886        seed = None
3887
3888        method = self._parse_var(tokens=(TokenType.ROW,), upper=True)
3889        matched_l_paren = self._match(TokenType.L_PAREN)
3890
3891        if self.TABLESAMPLE_CSV:
3892            num = None
3893            expressions = self._parse_csv(self._parse_primary)
3894        else:
3895            expressions = None
3896            num = (
3897                self._parse_factor()
3898                if self._match(TokenType.NUMBER, advance=False)
3899                else self._parse_primary() or self._parse_placeholder()
3900            )
3901
3902        if self._match_text_seq("BUCKET"):
3903            bucket_numerator = self._parse_number()
3904            self._match_text_seq("OUT", "OF")
3905            bucket_denominator = bucket_denominator = self._parse_number()
3906            self._match(TokenType.ON)
3907            bucket_field = self._parse_field()
3908        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
3909            percent = num
3910        elif self._match(TokenType.ROWS) or not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
3911            size = num
3912        else:
3913            percent = num
3914
3915        if matched_l_paren:
3916            self._match_r_paren()
3917
3918        if self._match(TokenType.L_PAREN):
3919            method = self._parse_var(upper=True)
3920            seed = self._match(TokenType.COMMA) and self._parse_number()
3921            self._match_r_paren()
3922        elif self._match_texts(("SEED", "REPEATABLE")):
3923            seed = self._parse_wrapped(self._parse_number)
3924
3925        if not method and self.DEFAULT_SAMPLING_METHOD:
3926            method = exp.var(self.DEFAULT_SAMPLING_METHOD)
3927
3928        return self.expression(
3929            exp.TableSample,
3930            expressions=expressions,
3931            method=method,
3932            bucket_numerator=bucket_numerator,
3933            bucket_denominator=bucket_denominator,
3934            bucket_field=bucket_field,
3935            percent=percent,
3936            size=size,
3937            seed=seed,
3938        )
3939
3940    def _parse_pivots(self) -> t.Optional[t.List[exp.Pivot]]:
3941        return list(iter(self._parse_pivot, None)) or None
3942
3943    def _parse_joins(self) -> t.Iterator[exp.Join]:
3944        return iter(self._parse_join, None)
3945
3946    # https://duckdb.org/docs/sql/statements/pivot
3947    def _parse_simplified_pivot(self) -> exp.Pivot:
3948        def _parse_on() -> t.Optional[exp.Expression]:
3949            this = self._parse_bitwise()
3950            return self._parse_in(this) if self._match(TokenType.IN) else this
3951
3952        this = self._parse_table()
3953        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
3954        using = self._match(TokenType.USING) and self._parse_csv(
3955            lambda: self._parse_alias(self._parse_function())
3956        )
3957        group = self._parse_group()
3958        return self.expression(
3959            exp.Pivot, this=this, expressions=expressions, using=using, group=group
3960        )
3961
3962    def _parse_pivot_in(self) -> exp.In | exp.PivotAny:
3963        def _parse_aliased_expression() -> t.Optional[exp.Expression]:
3964            this = self._parse_select_or_expression()
3965
3966            self._match(TokenType.ALIAS)
3967            alias = self._parse_bitwise()
3968            if alias:
3969                if isinstance(alias, exp.Column) and not alias.db:
3970                    alias = alias.this
3971                return self.expression(exp.PivotAlias, this=this, alias=alias)
3972
3973            return this
3974
3975        value = self._parse_column()
3976
3977        if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
3978            self.raise_error("Expecting IN (")
3979
3980        if self._match(TokenType.ANY):
3981            exprs: t.List[exp.Expression] = ensure_list(exp.PivotAny(this=self._parse_order()))
3982        else:
3983            exprs = self._parse_csv(_parse_aliased_expression)
3984
3985        self._match_r_paren()
3986        return self.expression(exp.In, this=value, expressions=exprs)
3987
3988    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
3989        index = self._index
3990        include_nulls = None
3991
3992        if self._match(TokenType.PIVOT):
3993            unpivot = False
3994        elif self._match(TokenType.UNPIVOT):
3995            unpivot = True
3996
3997            # https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
3998            if self._match_text_seq("INCLUDE", "NULLS"):
3999                include_nulls = True
4000            elif self._match_text_seq("EXCLUDE", "NULLS"):
4001                include_nulls = False
4002        else:
4003            return None
4004
4005        expressions = []
4006
4007        if not self._match(TokenType.L_PAREN):
4008            self._retreat(index)
4009            return None
4010
4011        if unpivot:
4012            expressions = self._parse_csv(self._parse_column)
4013        else:
4014            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
4015
4016        if not expressions:
4017            self.raise_error("Failed to parse PIVOT's aggregation list")
4018
4019        if not self._match(TokenType.FOR):
4020            self.raise_error("Expecting FOR")
4021
4022        field = self._parse_pivot_in()
4023        default_on_null = self._match_text_seq("DEFAULT", "ON", "NULL") and self._parse_wrapped(
4024            self._parse_bitwise
4025        )
4026
4027        self._match_r_paren()
4028
4029        pivot = self.expression(
4030            exp.Pivot,
4031            expressions=expressions,
4032            field=field,
4033            unpivot=unpivot,
4034            include_nulls=include_nulls,
4035            default_on_null=default_on_null,
4036        )
4037
4038        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
4039            pivot.set("alias", self._parse_table_alias())
4040
4041        if not unpivot:
4042            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
4043
4044            columns: t.List[exp.Expression] = []
4045            for fld in pivot.args["field"].expressions:
4046                field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
4047                for name in names:
4048                    if self.PREFIXED_PIVOT_COLUMNS:
4049                        name = f"{name}_{field_name}" if name else field_name
4050                    else:
4051                        name = f"{field_name}_{name}" if name else field_name
4052
4053                    columns.append(exp.to_identifier(name))
4054
4055            pivot.set("columns", columns)
4056
4057        return pivot
4058
4059    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
4060        return [agg.alias for agg in aggregations]
4061
4062    def _parse_prewhere(self, skip_where_token: bool = False) -> t.Optional[exp.PreWhere]:
4063        if not skip_where_token and not self._match(TokenType.PREWHERE):
4064            return None
4065
4066        return self.expression(
4067            exp.PreWhere, comments=self._prev_comments, this=self._parse_assignment()
4068        )
4069
4070    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
4071        if not skip_where_token and not self._match(TokenType.WHERE):
4072            return None
4073
4074        return self.expression(
4075            exp.Where, comments=self._prev_comments, this=self._parse_assignment()
4076        )
4077
4078    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
4079        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
4080            return None
4081
4082        elements: t.Dict[str, t.Any] = defaultdict(list)
4083
4084        if self._match(TokenType.ALL):
4085            elements["all"] = True
4086        elif self._match(TokenType.DISTINCT):
4087            elements["all"] = False
4088
4089        while True:
4090            index = self._index
4091
4092            elements["expressions"].extend(
4093                self._parse_csv(
4094                    lambda: None
4095                    if self._match_set((TokenType.CUBE, TokenType.ROLLUP), advance=False)
4096                    else self._parse_assignment()
4097                )
4098            )
4099
4100            before_with_index = self._index
4101            with_prefix = self._match(TokenType.WITH)
4102
4103            if self._match(TokenType.ROLLUP):
4104                elements["rollup"].append(
4105                    self._parse_cube_or_rollup(exp.Rollup, with_prefix=with_prefix)
4106                )
4107            elif self._match(TokenType.CUBE):
4108                elements["cube"].append(
4109                    self._parse_cube_or_rollup(exp.Cube, with_prefix=with_prefix)
4110                )
4111            elif self._match(TokenType.GROUPING_SETS):
4112                elements["grouping_sets"].append(
4113                    self.expression(
4114                        exp.GroupingSets,
4115                        expressions=self._parse_wrapped_csv(self._parse_grouping_set),
4116                    )
4117                )
4118            elif self._match_text_seq("TOTALS"):
4119                elements["totals"] = True  # type: ignore
4120
4121            if before_with_index <= self._index <= before_with_index + 1:
4122                self._retreat(before_with_index)
4123                break
4124
4125            if index == self._index:
4126                break
4127
4128        return self.expression(exp.Group, **elements)  # type: ignore
4129
4130    def _parse_cube_or_rollup(self, kind: t.Type[E], with_prefix: bool = False) -> E:
4131        return self.expression(
4132            kind, expressions=[] if with_prefix else self._parse_wrapped_csv(self._parse_column)
4133        )
4134
4135    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
4136        if self._match(TokenType.L_PAREN):
4137            grouping_set = self._parse_csv(self._parse_column)
4138            self._match_r_paren()
4139            return self.expression(exp.Tuple, expressions=grouping_set)
4140
4141        return self._parse_column()
4142
4143    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
4144        if not skip_having_token and not self._match(TokenType.HAVING):
4145            return None
4146        return self.expression(exp.Having, this=self._parse_assignment())
4147
4148    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
4149        if not self._match(TokenType.QUALIFY):
4150            return None
4151        return self.expression(exp.Qualify, this=self._parse_assignment())
4152
4153    def _parse_connect(self, skip_start_token: bool = False) -> t.Optional[exp.Connect]:
4154        if skip_start_token:
4155            start = None
4156        elif self._match(TokenType.START_WITH):
4157            start = self._parse_assignment()
4158        else:
4159            return None
4160
4161        self._match(TokenType.CONNECT_BY)
4162        nocycle = self._match_text_seq("NOCYCLE")
4163        self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
4164            exp.Prior, this=self._parse_bitwise()
4165        )
4166        connect = self._parse_assignment()
4167        self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
4168
4169        if not start and self._match(TokenType.START_WITH):
4170            start = self._parse_assignment()
4171
4172        return self.expression(exp.Connect, start=start, connect=connect, nocycle=nocycle)
4173
4174    def _parse_name_as_expression(self) -> t.Optional[exp.Expression]:
4175        this = self._parse_id_var(any_token=True)
4176        if self._match(TokenType.ALIAS):
4177            this = self.expression(exp.Alias, alias=this, this=self._parse_assignment())
4178        return this
4179
4180    def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
4181        if self._match_text_seq("INTERPOLATE"):
4182            return self._parse_wrapped_csv(self._parse_name_as_expression)
4183        return None
4184
4185    def _parse_order(
4186        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
4187    ) -> t.Optional[exp.Expression]:
4188        siblings = None
4189        if not skip_order_token and not self._match(TokenType.ORDER_BY):
4190            if not self._match(TokenType.ORDER_SIBLINGS_BY):
4191                return this
4192
4193            siblings = True
4194
4195        return self.expression(
4196            exp.Order,
4197            this=this,
4198            expressions=self._parse_csv(self._parse_ordered),
4199            siblings=siblings,
4200        )
4201
4202    def _parse_sort(self, exp_class: t.Type[E], token: TokenType) -> t.Optional[E]:
4203        if not self._match(token):
4204            return None
4205        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
4206
4207    def _parse_ordered(
4208        self, parse_method: t.Optional[t.Callable] = None
4209    ) -> t.Optional[exp.Ordered]:
4210        this = parse_method() if parse_method else self._parse_assignment()
4211        if not this:
4212            return None
4213
4214        if this.name.upper() == "ALL" and self.dialect.SUPPORTS_ORDER_BY_ALL:
4215            this = exp.var("ALL")
4216
4217        asc = self._match(TokenType.ASC)
4218        desc = self._match(TokenType.DESC) or (asc and False)
4219
4220        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
4221        is_nulls_last = self._match_text_seq("NULLS", "LAST")
4222
4223        nulls_first = is_nulls_first or False
4224        explicitly_null_ordered = is_nulls_first or is_nulls_last
4225
4226        if (
4227            not explicitly_null_ordered
4228            and (
4229                (not desc and self.dialect.NULL_ORDERING == "nulls_are_small")
4230                or (desc and self.dialect.NULL_ORDERING != "nulls_are_small")
4231            )
4232            and self.dialect.NULL_ORDERING != "nulls_are_last"
4233        ):
4234            nulls_first = True
4235
4236        if self._match_text_seq("WITH", "FILL"):
4237            with_fill = self.expression(
4238                exp.WithFill,
4239                **{  # type: ignore
4240                    "from": self._match(TokenType.FROM) and self._parse_bitwise(),
4241                    "to": self._match_text_seq("TO") and self._parse_bitwise(),
4242                    "step": self._match_text_seq("STEP") and self._parse_bitwise(),
4243                    "interpolate": self._parse_interpolate(),
4244                },
4245            )
4246        else:
4247            with_fill = None
4248
4249        return self.expression(
4250            exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
4251        )
4252
4253    def _parse_limit(
4254        self,
4255        this: t.Optional[exp.Expression] = None,
4256        top: bool = False,
4257        skip_limit_token: bool = False,
4258    ) -> t.Optional[exp.Expression]:
4259        if skip_limit_token or self._match(TokenType.TOP if top else TokenType.LIMIT):
4260            comments = self._prev_comments
4261            if top:
4262                limit_paren = self._match(TokenType.L_PAREN)
4263                expression = self._parse_term() if limit_paren else self._parse_number()
4264
4265                if limit_paren:
4266                    self._match_r_paren()
4267            else:
4268                expression = self._parse_term()
4269
4270            if self._match(TokenType.COMMA):
4271                offset = expression
4272                expression = self._parse_term()
4273            else:
4274                offset = None
4275
4276            limit_exp = self.expression(
4277                exp.Limit,
4278                this=this,
4279                expression=expression,
4280                offset=offset,
4281                comments=comments,
4282                expressions=self._parse_limit_by(),
4283            )
4284
4285            return limit_exp
4286
4287        if self._match(TokenType.FETCH):
4288            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
4289            direction = self._prev.text.upper() if direction else "FIRST"
4290
4291            count = self._parse_field(tokens=self.FETCH_TOKENS)
4292            percent = self._match(TokenType.PERCENT)
4293
4294            self._match_set((TokenType.ROW, TokenType.ROWS))
4295
4296            only = self._match_text_seq("ONLY")
4297            with_ties = self._match_text_seq("WITH", "TIES")
4298
4299            if only and with_ties:
4300                self.raise_error("Cannot specify both ONLY and WITH TIES in FETCH clause")
4301
4302            return self.expression(
4303                exp.Fetch,
4304                direction=direction,
4305                count=count,
4306                percent=percent,
4307                with_ties=with_ties,
4308            )
4309
4310        return this
4311
4312    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4313        if not self._match(TokenType.OFFSET):
4314            return this
4315
4316        count = self._parse_term()
4317        self._match_set((TokenType.ROW, TokenType.ROWS))
4318
4319        return self.expression(
4320            exp.Offset, this=this, expression=count, expressions=self._parse_limit_by()
4321        )
4322
4323    def _parse_limit_by(self) -> t.Optional[t.List[exp.Expression]]:
4324        return self._match_text_seq("BY") and self._parse_csv(self._parse_bitwise)
4325
4326    def _parse_locks(self) -> t.List[exp.Lock]:
4327        locks = []
4328        while True:
4329            if self._match_text_seq("FOR", "UPDATE"):
4330                update = True
4331            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
4332                "LOCK", "IN", "SHARE", "MODE"
4333            ):
4334                update = False
4335            else:
4336                break
4337
4338            expressions = None
4339            if self._match_text_seq("OF"):
4340                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
4341
4342            wait: t.Optional[bool | exp.Expression] = None
4343            if self._match_text_seq("NOWAIT"):
4344                wait = True
4345            elif self._match_text_seq("WAIT"):
4346                wait = self._parse_primary()
4347            elif self._match_text_seq("SKIP", "LOCKED"):
4348                wait = False
4349
4350            locks.append(
4351                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
4352            )
4353
4354        return locks
4355
4356    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4357        while this and self._match_set(self.SET_OPERATIONS):
4358            token_type = self._prev.token_type
4359
4360            if token_type == TokenType.UNION:
4361                operation: t.Type[exp.SetOperation] = exp.Union
4362            elif token_type == TokenType.EXCEPT:
4363                operation = exp.Except
4364            else:
4365                operation = exp.Intersect
4366
4367            comments = self._prev.comments
4368
4369            if self._match(TokenType.DISTINCT):
4370                distinct: t.Optional[bool] = True
4371            elif self._match(TokenType.ALL):
4372                distinct = False
4373            else:
4374                distinct = self.dialect.SET_OP_DISTINCT_BY_DEFAULT[operation]
4375                if distinct is None:
4376                    self.raise_error(f"Expected DISTINCT or ALL for {operation.__name__}")
4377
4378            by_name = self._match_text_seq("BY", "NAME")
4379            expression = self._parse_select(nested=True, parse_set_operation=False)
4380
4381            this = self.expression(
4382                operation,
4383                comments=comments,
4384                this=this,
4385                distinct=distinct,
4386                by_name=by_name,
4387                expression=expression,
4388            )
4389
4390        if isinstance(this, exp.SetOperation) and self.MODIFIERS_ATTACHED_TO_SET_OP:
4391            expression = this.expression
4392
4393            if expression:
4394                for arg in self.SET_OP_MODIFIERS:
4395                    expr = expression.args.get(arg)
4396                    if expr:
4397                        this.set(arg, expr.pop())
4398
4399        return this
4400
4401    def _parse_expression(self) -> t.Optional[exp.Expression]:
4402        return self._parse_alias(self._parse_assignment())
4403
4404    def _parse_assignment(self) -> t.Optional[exp.Expression]:
4405        this = self._parse_disjunction()
4406        if not this and self._next and self._next.token_type in self.ASSIGNMENT:
4407            # This allows us to parse <non-identifier token> := <expr>
4408            this = exp.column(
4409                t.cast(str, self._advance_any(ignore_reserved=True) and self._prev.text)
4410            )
4411
4412        while self._match_set(self.ASSIGNMENT):
4413            if isinstance(this, exp.Column) and len(this.parts) == 1:
4414                this = this.this
4415
4416            this = self.expression(
4417                self.ASSIGNMENT[self._prev.token_type],
4418                this=this,
4419                comments=self._prev_comments,
4420                expression=self._parse_assignment(),
4421            )
4422
4423        return this
4424
4425    def _parse_disjunction(self) -> t.Optional[exp.Expression]:
4426        return self._parse_tokens(self._parse_conjunction, self.DISJUNCTION)
4427
4428    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
4429        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
4430
4431    def _parse_equality(self) -> t.Optional[exp.Expression]:
4432        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
4433
4434    def _parse_comparison(self) -> t.Optional[exp.Expression]:
4435        return self._parse_tokens(self._parse_range, self.COMPARISON)
4436
4437    def _parse_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4438        this = this or self._parse_bitwise()
4439        negate = self._match(TokenType.NOT)
4440
4441        if self._match_set(self.RANGE_PARSERS):
4442            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
4443            if not expression:
4444                return this
4445
4446            this = expression
4447        elif self._match(TokenType.ISNULL):
4448            this = self.expression(exp.Is, this=this, expression=exp.Null())
4449
4450        # Postgres supports ISNULL and NOTNULL for conditions.
4451        # https://blog.andreiavram.ro/postgresql-null-composite-type/
4452        if self._match(TokenType.NOTNULL):
4453            this = self.expression(exp.Is, this=this, expression=exp.Null())
4454            this = self.expression(exp.Not, this=this)
4455
4456        if negate:
4457            this = self._negate_range(this)
4458
4459        if self._match(TokenType.IS):
4460            this = self._parse_is(this)
4461
4462        return this
4463
4464    def _negate_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4465        if not this:
4466            return this
4467
4468        return self.expression(exp.Not, this=this)
4469
4470    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4471        index = self._index - 1
4472        negate = self._match(TokenType.NOT)
4473
4474        if self._match_text_seq("DISTINCT", "FROM"):
4475            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
4476            return self.expression(klass, this=this, expression=self._parse_bitwise())
4477
4478        if self._match(TokenType.JSON):
4479            kind = self._match_texts(self.IS_JSON_PREDICATE_KIND) and self._prev.text.upper()
4480
4481            if self._match_text_seq("WITH"):
4482                _with = True
4483            elif self._match_text_seq("WITHOUT"):
4484                _with = False
4485            else:
4486                _with = None
4487
4488            unique = self._match(TokenType.UNIQUE)
4489            self._match_text_seq("KEYS")
4490            expression: t.Optional[exp.Expression] = self.expression(
4491                exp.JSON, **{"this": kind, "with": _with, "unique": unique}
4492            )
4493        else:
4494            expression = self._parse_primary() or self._parse_null()
4495            if not expression:
4496                self._retreat(index)
4497                return None
4498
4499        this = self.expression(exp.Is, this=this, expression=expression)
4500        return self.expression(exp.Not, this=this) if negate else this
4501
4502    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
4503        unnest = self._parse_unnest(with_alias=False)
4504        if unnest:
4505            this = self.expression(exp.In, this=this, unnest=unnest)
4506        elif self._match_set((TokenType.L_PAREN, TokenType.L_BRACKET)):
4507            matched_l_paren = self._prev.token_type == TokenType.L_PAREN
4508            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
4509
4510            if len(expressions) == 1 and isinstance(expressions[0], exp.Query):
4511                this = self.expression(exp.In, this=this, query=expressions[0].subquery(copy=False))
4512            else:
4513                this = self.expression(exp.In, this=this, expressions=expressions)
4514
4515            if matched_l_paren:
4516                self._match_r_paren(this)
4517            elif not self._match(TokenType.R_BRACKET, expression=this):
4518                self.raise_error("Expecting ]")
4519        else:
4520            this = self.expression(exp.In, this=this, field=self._parse_column())
4521
4522        return this
4523
4524    def _parse_between(self, this: t.Optional[exp.Expression]) -> exp.Between:
4525        low = self._parse_bitwise()
4526        self._match(TokenType.AND)
4527        high = self._parse_bitwise()
4528        return self.expression(exp.Between, this=this, low=low, high=high)
4529
4530    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4531        if not self._match(TokenType.ESCAPE):
4532            return this
4533        return self.expression(exp.Escape, this=this, expression=self._parse_string())
4534
4535    def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Add | exp.Interval]:
4536        index = self._index
4537
4538        if not self._match(TokenType.INTERVAL) and match_interval:
4539            return None
4540
4541        if self._match(TokenType.STRING, advance=False):
4542            this = self._parse_primary()
4543        else:
4544            this = self._parse_term()
4545
4546        if not this or (
4547            isinstance(this, exp.Column)
4548            and not this.table
4549            and not this.this.quoted
4550            and this.name.upper() == "IS"
4551        ):
4552            self._retreat(index)
4553            return None
4554
4555        unit = self._parse_function() or (
4556            not self._match(TokenType.ALIAS, advance=False)
4557            and self._parse_var(any_token=True, upper=True)
4558        )
4559
4560        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
4561        # each INTERVAL expression into this canonical form so it's easy to transpile
4562        if this and this.is_number:
4563            this = exp.Literal.string(this.to_py())
4564        elif this and this.is_string:
4565            parts = exp.INTERVAL_STRING_RE.findall(this.name)
4566            if len(parts) == 1:
4567                if unit:
4568                    # Unconsume the eagerly-parsed unit, since the real unit was part of the string
4569                    self._retreat(self._index - 1)
4570
4571                this = exp.Literal.string(parts[0][0])
4572                unit = self.expression(exp.Var, this=parts[0][1].upper())
4573
4574        if self.INTERVAL_SPANS and self._match_text_seq("TO"):
4575            unit = self.expression(
4576                exp.IntervalSpan, this=unit, expression=self._parse_var(any_token=True, upper=True)
4577            )
4578
4579        interval = self.expression(exp.Interval, this=this, unit=unit)
4580
4581        index = self._index
4582        self._match(TokenType.PLUS)
4583
4584        # Convert INTERVAL 'val_1' unit_1 [+] ... [+] 'val_n' unit_n into a sum of intervals
4585        if self._match_set((TokenType.STRING, TokenType.NUMBER), advance=False):
4586            return self.expression(
4587                exp.Add, this=interval, expression=self._parse_interval(match_interval=False)
4588            )
4589
4590        self._retreat(index)
4591        return interval
4592
4593    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
4594        this = self._parse_term()
4595
4596        while True:
4597            if self._match_set(self.BITWISE):
4598                this = self.expression(
4599                    self.BITWISE[self._prev.token_type],
4600                    this=this,
4601                    expression=self._parse_term(),
4602                )
4603            elif self.dialect.DPIPE_IS_STRING_CONCAT and self._match(TokenType.DPIPE):
4604                this = self.expression(
4605                    exp.DPipe,
4606                    this=this,
4607                    expression=self._parse_term(),
4608                    safe=not self.dialect.STRICT_STRING_CONCAT,
4609                )
4610            elif self._match(TokenType.DQMARK):
4611                this = self.expression(
4612                    exp.Coalesce, this=this, expressions=ensure_list(self._parse_term())
4613                )
4614            elif self._match_pair(TokenType.LT, TokenType.LT):
4615                this = self.expression(
4616                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
4617                )
4618            elif self._match_pair(TokenType.GT, TokenType.GT):
4619                this = self.expression(
4620                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
4621                )
4622            else:
4623                break
4624
4625        return this
4626
4627    def _parse_term(self) -> t.Optional[exp.Expression]:
4628        this = self._parse_factor()
4629
4630        while self._match_set(self.TERM):
4631            klass = self.TERM[self._prev.token_type]
4632            comments = self._prev_comments
4633            expression = self._parse_factor()
4634
4635            this = self.expression(klass, this=this, comments=comments, expression=expression)
4636
4637            if isinstance(this, exp.Collate):
4638                expr = this.expression
4639
4640                # Preserve collations such as pg_catalog."default" (Postgres) as columns, otherwise
4641                # fallback to Identifier / Var
4642                if isinstance(expr, exp.Column) and len(expr.parts) == 1:
4643                    ident = expr.this
4644                    if isinstance(ident, exp.Identifier):
4645                        this.set("expression", ident if ident.quoted else exp.var(ident.name))
4646
4647        return this
4648
4649    def _parse_factor(self) -> t.Optional[exp.Expression]:
4650        parse_method = self._parse_exponent if self.EXPONENT else self._parse_unary
4651        this = parse_method()
4652
4653        while self._match_set(self.FACTOR):
4654            klass = self.FACTOR[self._prev.token_type]
4655            comments = self._prev_comments
4656            expression = parse_method()
4657
4658            if not expression and klass is exp.IntDiv and self._prev.text.isalpha():
4659                self._retreat(self._index - 1)
4660                return this
4661
4662            this = self.expression(klass, this=this, comments=comments, expression=expression)
4663
4664            if isinstance(this, exp.Div):
4665                this.args["typed"] = self.dialect.TYPED_DIVISION
4666                this.args["safe"] = self.dialect.SAFE_DIVISION
4667
4668        return this
4669
4670    def _parse_exponent(self) -> t.Optional[exp.Expression]:
4671        return self._parse_tokens(self._parse_unary, self.EXPONENT)
4672
4673    def _parse_unary(self) -> t.Optional[exp.Expression]:
4674        if self._match_set(self.UNARY_PARSERS):
4675            return self.UNARY_PARSERS[self._prev.token_type](self)
4676        return self._parse_at_time_zone(self._parse_type())
4677
4678    def _parse_type(
4679        self, parse_interval: bool = True, fallback_to_identifier: bool = False
4680    ) -> t.Optional[exp.Expression]:
4681        interval = parse_interval and self._parse_interval()
4682        if interval:
4683            return interval
4684
4685        index = self._index
4686        data_type = self._parse_types(check_func=True, allow_identifiers=False)
4687
4688        # parse_types() returns a Cast if we parsed BQ's inline constructor <type>(<values>) e.g.
4689        # STRUCT<a INT, b STRING>(1, 'foo'), which is canonicalized to CAST(<values> AS <type>)
4690        if isinstance(data_type, exp.Cast):
4691            # This constructor can contain ops directly after it, for instance struct unnesting:
4692            # STRUCT<a INT, b STRING>(1, 'foo').* --> CAST(STRUCT(1, 'foo') AS STRUCT<a iNT, b STRING).*
4693            return self._parse_column_ops(data_type)
4694
4695        if data_type:
4696            index2 = self._index
4697            this = self._parse_primary()
4698
4699            if isinstance(this, exp.Literal):
4700                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
4701                if parser:
4702                    return parser(self, this, data_type)
4703
4704                return self.expression(exp.Cast, this=this, to=data_type)
4705
4706            # The expressions arg gets set by the parser when we have something like DECIMAL(38, 0)
4707            # in the input SQL. In that case, we'll produce these tokens: DECIMAL ( 38 , 0 )
4708            #
4709            # If the index difference here is greater than 1, that means the parser itself must have
4710            # consumed additional tokens such as the DECIMAL scale and precision in the above example.
4711            #
4712            # If it's not greater than 1, then it must be 1, because we've consumed at least the type
4713            # keyword, meaning that the expressions arg of the DataType must have gotten set by a
4714            # callable in the TYPE_CONVERTERS mapping. For example, Snowflake converts DECIMAL to
4715            # DECIMAL(38, 0)) in order to facilitate the data type's transpilation.
4716            #
4717            # In these cases, we don't really want to return the converted type, but instead retreat
4718            # and try to parse a Column or Identifier in the section below.
4719            if data_type.expressions and index2 - index > 1:
4720                self._retreat(index2)
4721                return self._parse_column_ops(data_type)
4722
4723            self._retreat(index)
4724
4725        if fallback_to_identifier:
4726            return self._parse_id_var()
4727
4728        this = self._parse_column()
4729        return this and self._parse_column_ops(this)
4730
4731    def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
4732        this = self._parse_type()
4733        if not this:
4734            return None
4735
4736        if isinstance(this, exp.Column) and not this.table:
4737            this = exp.var(this.name.upper())
4738
4739        return self.expression(
4740            exp.DataTypeParam, this=this, expression=self._parse_var(any_token=True)
4741        )
4742
4743    def _parse_types(
4744        self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
4745    ) -> t.Optional[exp.Expression]:
4746        index = self._index
4747
4748        this: t.Optional[exp.Expression] = None
4749        prefix = self._match_text_seq("SYSUDTLIB", ".")
4750
4751        if not self._match_set(self.TYPE_TOKENS):
4752            identifier = allow_identifiers and self._parse_id_var(
4753                any_token=False, tokens=(TokenType.VAR,)
4754            )
4755            if isinstance(identifier, exp.Identifier):
4756                tokens = self.dialect.tokenize(identifier.sql(dialect=self.dialect))
4757
4758                if len(tokens) != 1:
4759                    self.raise_error("Unexpected identifier", self._prev)
4760
4761                if tokens[0].token_type in self.TYPE_TOKENS:
4762                    self._prev = tokens[0]
4763                elif self.dialect.SUPPORTS_USER_DEFINED_TYPES:
4764                    type_name = identifier.name
4765
4766                    while self._match(TokenType.DOT):
4767                        type_name = f"{type_name}.{self._advance_any() and self._prev.text}"
4768
4769                    this = exp.DataType.build(type_name, udt=True)
4770                else:
4771                    self._retreat(self._index - 1)
4772                    return None
4773            else:
4774                return None
4775
4776        type_token = self._prev.token_type
4777
4778        if type_token == TokenType.PSEUDO_TYPE:
4779            return self.expression(exp.PseudoType, this=self._prev.text.upper())
4780
4781        if type_token == TokenType.OBJECT_IDENTIFIER:
4782            return self.expression(exp.ObjectIdentifier, this=self._prev.text.upper())
4783
4784        # https://materialize.com/docs/sql/types/map/
4785        if type_token == TokenType.MAP and self._match(TokenType.L_BRACKET):
4786            key_type = self._parse_types(
4787                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4788            )
4789            if not self._match(TokenType.FARROW):
4790                self._retreat(index)
4791                return None
4792
4793            value_type = self._parse_types(
4794                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4795            )
4796            if not self._match(TokenType.R_BRACKET):
4797                self._retreat(index)
4798                return None
4799
4800            return exp.DataType(
4801                this=exp.DataType.Type.MAP,
4802                expressions=[key_type, value_type],
4803                nested=True,
4804                prefix=prefix,
4805            )
4806
4807        nested = type_token in self.NESTED_TYPE_TOKENS
4808        is_struct = type_token in self.STRUCT_TYPE_TOKENS
4809        is_aggregate = type_token in self.AGGREGATE_TYPE_TOKENS
4810        expressions = None
4811        maybe_func = False
4812
4813        if self._match(TokenType.L_PAREN):
4814            if is_struct:
4815                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
4816            elif nested:
4817                expressions = self._parse_csv(
4818                    lambda: self._parse_types(
4819                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4820                    )
4821                )
4822                if type_token == TokenType.NULLABLE and len(expressions) == 1:
4823                    this = expressions[0]
4824                    this.set("nullable", True)
4825                    self._match_r_paren()
4826                    return this
4827            elif type_token in self.ENUM_TYPE_TOKENS:
4828                expressions = self._parse_csv(self._parse_equality)
4829            elif is_aggregate:
4830                func_or_ident = self._parse_function(anonymous=True) or self._parse_id_var(
4831                    any_token=False, tokens=(TokenType.VAR,)
4832                )
4833                if not func_or_ident or not self._match(TokenType.COMMA):
4834                    return None
4835                expressions = self._parse_csv(
4836                    lambda: self._parse_types(
4837                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4838                    )
4839                )
4840                expressions.insert(0, func_or_ident)
4841            else:
4842                expressions = self._parse_csv(self._parse_type_size)
4843
4844                # https://docs.snowflake.com/en/sql-reference/data-types-vector
4845                if type_token == TokenType.VECTOR and len(expressions) == 2:
4846                    expressions[0] = exp.DataType.build(expressions[0].name, dialect=self.dialect)
4847
4848            if not expressions or not self._match(TokenType.R_PAREN):
4849                self._retreat(index)
4850                return None
4851
4852            maybe_func = True
4853
4854        values: t.Optional[t.List[exp.Expression]] = None
4855
4856        if nested and self._match(TokenType.LT):
4857            if is_struct:
4858                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
4859            else:
4860                expressions = self._parse_csv(
4861                    lambda: self._parse_types(
4862                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4863                    )
4864                )
4865
4866            if not self._match(TokenType.GT):
4867                self.raise_error("Expecting >")
4868
4869            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
4870                values = self._parse_csv(self._parse_assignment)
4871                if not values and is_struct:
4872                    values = None
4873                    self._retreat(self._index - 1)
4874                else:
4875                    self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
4876
4877        if type_token in self.TIMESTAMPS:
4878            if self._match_text_seq("WITH", "TIME", "ZONE"):
4879                maybe_func = False
4880                tz_type = (
4881                    exp.DataType.Type.TIMETZ
4882                    if type_token in self.TIMES
4883                    else exp.DataType.Type.TIMESTAMPTZ
4884                )
4885                this = exp.DataType(this=tz_type, expressions=expressions)
4886            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
4887                maybe_func = False
4888                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
4889            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
4890                maybe_func = False
4891        elif type_token == TokenType.INTERVAL:
4892            unit = self._parse_var(upper=True)
4893            if unit:
4894                if self._match_text_seq("TO"):
4895                    unit = exp.IntervalSpan(this=unit, expression=self._parse_var(upper=True))
4896
4897                this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
4898            else:
4899                this = self.expression(exp.DataType, this=exp.DataType.Type.INTERVAL)
4900
4901        if maybe_func and check_func:
4902            index2 = self._index
4903            peek = self._parse_string()
4904
4905            if not peek:
4906                self._retreat(index)
4907                return None
4908
4909            self._retreat(index2)
4910
4911        if not this:
4912            if self._match_text_seq("UNSIGNED"):
4913                unsigned_type_token = self.SIGNED_TO_UNSIGNED_TYPE_TOKEN.get(type_token)
4914                if not unsigned_type_token:
4915                    self.raise_error(f"Cannot convert {type_token.value} to unsigned.")
4916
4917                type_token = unsigned_type_token or type_token
4918
4919            this = exp.DataType(
4920                this=exp.DataType.Type[type_token.value],
4921                expressions=expressions,
4922                nested=nested,
4923                prefix=prefix,
4924            )
4925
4926            # Empty arrays/structs are allowed
4927            if values is not None:
4928                cls = exp.Struct if is_struct else exp.Array
4929                this = exp.cast(cls(expressions=values), this, copy=False)
4930
4931        elif expressions:
4932            this.set("expressions", expressions)
4933
4934        # https://materialize.com/docs/sql/types/list/#type-name
4935        while self._match(TokenType.LIST):
4936            this = exp.DataType(this=exp.DataType.Type.LIST, expressions=[this], nested=True)
4937
4938        index = self._index
4939
4940        # Postgres supports the INT ARRAY[3] syntax as a synonym for INT[3]
4941        matched_array = self._match(TokenType.ARRAY)
4942
4943        while self._curr:
4944            datatype_token = self._prev.token_type
4945            matched_l_bracket = self._match(TokenType.L_BRACKET)
4946            if not matched_l_bracket and not matched_array:
4947                break
4948
4949            matched_array = False
4950            values = self._parse_csv(self._parse_assignment) or None
4951            if (
4952                values
4953                and not schema
4954                and (
4955                    not self.dialect.SUPPORTS_FIXED_SIZE_ARRAYS or datatype_token == TokenType.ARRAY
4956                )
4957            ):
4958                # Retreating here means that we should not parse the following values as part of the data type, e.g. in DuckDB
4959                # 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
4960                self._retreat(index)
4961                break
4962
4963            this = exp.DataType(
4964                this=exp.DataType.Type.ARRAY, expressions=[this], values=values, nested=True
4965            )
4966            self._match(TokenType.R_BRACKET)
4967
4968        if self.TYPE_CONVERTERS and isinstance(this.this, exp.DataType.Type):
4969            converter = self.TYPE_CONVERTERS.get(this.this)
4970            if converter:
4971                this = converter(t.cast(exp.DataType, this))
4972
4973        return this
4974
4975    def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
4976        index = self._index
4977
4978        if (
4979            self._curr
4980            and self._next
4981            and self._curr.token_type in self.TYPE_TOKENS
4982            and self._next.token_type in self.TYPE_TOKENS
4983        ):
4984            # Takes care of special cases like `STRUCT<list ARRAY<...>>` where the identifier is also a
4985            # type token. Without this, the list will be parsed as a type and we'll eventually crash
4986            this = self._parse_id_var()
4987        else:
4988            this = (
4989                self._parse_type(parse_interval=False, fallback_to_identifier=True)
4990                or self._parse_id_var()
4991            )
4992
4993        self._match(TokenType.COLON)
4994
4995        if (
4996            type_required
4997            and not isinstance(this, exp.DataType)
4998            and not self._match_set(self.TYPE_TOKENS, advance=False)
4999        ):
5000            self._retreat(index)
5001            return self._parse_types()
5002
5003        return self._parse_column_def(this)
5004
5005    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5006        if not self._match_text_seq("AT", "TIME", "ZONE"):
5007            return this
5008        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
5009
5010    def _parse_column(self) -> t.Optional[exp.Expression]:
5011        this = self._parse_column_reference()
5012        column = self._parse_column_ops(this) if this else self._parse_bracket(this)
5013
5014        if self.dialect.SUPPORTS_COLUMN_JOIN_MARKS and column:
5015            column.set("join_mark", self._match(TokenType.JOIN_MARKER))
5016
5017        return column
5018
5019    def _parse_column_reference(self) -> t.Optional[exp.Expression]:
5020        this = self._parse_field()
5021        if (
5022            not this
5023            and self._match(TokenType.VALUES, advance=False)
5024            and self.VALUES_FOLLOWED_BY_PAREN
5025            and (not self._next or self._next.token_type != TokenType.L_PAREN)
5026        ):
5027            this = self._parse_id_var()
5028
5029        if isinstance(this, exp.Identifier):
5030            # We bubble up comments from the Identifier to the Column
5031            this = self.expression(exp.Column, comments=this.pop_comments(), this=this)
5032
5033        return this
5034
5035    def _parse_colon_as_variant_extract(
5036        self, this: t.Optional[exp.Expression]
5037    ) -> t.Optional[exp.Expression]:
5038        casts = []
5039        json_path = []
5040        escape = None
5041
5042        while self._match(TokenType.COLON):
5043            start_index = self._index
5044
5045            # Snowflake allows reserved keywords as json keys but advance_any() excludes TokenType.SELECT from any_tokens=True
5046            path = self._parse_column_ops(
5047                self._parse_field(any_token=True, tokens=(TokenType.SELECT,))
5048            )
5049
5050            # The cast :: operator has a lower precedence than the extraction operator :, so
5051            # we rearrange the AST appropriately to avoid casting the JSON path
5052            while isinstance(path, exp.Cast):
5053                casts.append(path.to)
5054                path = path.this
5055
5056            if casts:
5057                dcolon_offset = next(
5058                    i
5059                    for i, t in enumerate(self._tokens[start_index:])
5060                    if t.token_type == TokenType.DCOLON
5061                )
5062                end_token = self._tokens[start_index + dcolon_offset - 1]
5063            else:
5064                end_token = self._prev
5065
5066            if path:
5067                # Escape single quotes from Snowflake's colon extraction (e.g. col:"a'b") as
5068                # it'll roundtrip to a string literal in GET_PATH
5069                if isinstance(path, exp.Identifier) and path.quoted:
5070                    escape = True
5071
5072                json_path.append(self._find_sql(self._tokens[start_index], end_token))
5073
5074        # The VARIANT extract in Snowflake/Databricks is parsed as a JSONExtract; Snowflake uses the json_path in GET_PATH() while
5075        # Databricks transforms it back to the colon/dot notation
5076        if json_path:
5077            json_path_expr = self.dialect.to_json_path(exp.Literal.string(".".join(json_path)))
5078
5079            if json_path_expr:
5080                json_path_expr.set("escape", escape)
5081
5082            this = self.expression(
5083                exp.JSONExtract,
5084                this=this,
5085                expression=json_path_expr,
5086                variant_extract=True,
5087            )
5088
5089            while casts:
5090                this = self.expression(exp.Cast, this=this, to=casts.pop())
5091
5092        return this
5093
5094    def _parse_dcolon(self) -> t.Optional[exp.Expression]:
5095        return self._parse_types()
5096
5097    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5098        this = self._parse_bracket(this)
5099
5100        while self._match_set(self.COLUMN_OPERATORS):
5101            op_token = self._prev.token_type
5102            op = self.COLUMN_OPERATORS.get(op_token)
5103
5104            if op_token == TokenType.DCOLON:
5105                field = self._parse_dcolon()
5106                if not field:
5107                    self.raise_error("Expected type")
5108            elif op and self._curr:
5109                field = self._parse_column_reference() or self._parse_bracket()
5110            else:
5111                field = self._parse_field(any_token=True, anonymous_func=True)
5112
5113            if isinstance(field, exp.Func) and this:
5114                # bigquery allows function calls like x.y.count(...)
5115                # SAFE.SUBSTR(...)
5116                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
5117                this = exp.replace_tree(
5118                    this,
5119                    lambda n: (
5120                        self.expression(exp.Dot, this=n.args.get("table"), expression=n.this)
5121                        if n.table
5122                        else n.this
5123                    )
5124                    if isinstance(n, exp.Column)
5125                    else n,
5126                )
5127
5128            if op:
5129                this = op(self, this, field)
5130            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
5131                this = self.expression(
5132                    exp.Column,
5133                    comments=this.comments,
5134                    this=field,
5135                    table=this.this,
5136                    db=this.args.get("table"),
5137                    catalog=this.args.get("db"),
5138                )
5139            else:
5140                this = self.expression(exp.Dot, this=this, expression=field)
5141
5142            this = self._parse_bracket(this)
5143
5144        return self._parse_colon_as_variant_extract(this) if self.COLON_IS_VARIANT_EXTRACT else this
5145
5146    def _parse_primary(self) -> t.Optional[exp.Expression]:
5147        if self._match_set(self.PRIMARY_PARSERS):
5148            token_type = self._prev.token_type
5149            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
5150
5151            if token_type == TokenType.STRING:
5152                expressions = [primary]
5153                while self._match(TokenType.STRING):
5154                    expressions.append(exp.Literal.string(self._prev.text))
5155
5156                if len(expressions) > 1:
5157                    return self.expression(exp.Concat, expressions=expressions)
5158
5159            return primary
5160
5161        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
5162            return exp.Literal.number(f"0.{self._prev.text}")
5163
5164        if self._match(TokenType.L_PAREN):
5165            comments = self._prev_comments
5166            query = self._parse_select()
5167
5168            if query:
5169                expressions = [query]
5170            else:
5171                expressions = self._parse_expressions()
5172
5173            this = self._parse_query_modifiers(seq_get(expressions, 0))
5174
5175            if not this and self._match(TokenType.R_PAREN, advance=False):
5176                this = self.expression(exp.Tuple)
5177            elif isinstance(this, exp.UNWRAPPED_QUERIES):
5178                this = self._parse_subquery(this=this, parse_alias=False)
5179            elif isinstance(this, exp.Subquery):
5180                this = self._parse_subquery(
5181                    this=self._parse_set_operations(this), parse_alias=False
5182                )
5183            elif len(expressions) > 1 or self._prev.token_type == TokenType.COMMA:
5184                this = self.expression(exp.Tuple, expressions=expressions)
5185            else:
5186                this = self.expression(exp.Paren, this=this)
5187
5188            if this:
5189                this.add_comments(comments)
5190
5191            self._match_r_paren(expression=this)
5192            return this
5193
5194        return None
5195
5196    def _parse_field(
5197        self,
5198        any_token: bool = False,
5199        tokens: t.Optional[t.Collection[TokenType]] = None,
5200        anonymous_func: bool = False,
5201    ) -> t.Optional[exp.Expression]:
5202        if anonymous_func:
5203            field = (
5204                self._parse_function(anonymous=anonymous_func, any_token=any_token)
5205                or self._parse_primary()
5206            )
5207        else:
5208            field = self._parse_primary() or self._parse_function(
5209                anonymous=anonymous_func, any_token=any_token
5210            )
5211        return field or self._parse_id_var(any_token=any_token, tokens=tokens)
5212
5213    def _parse_function(
5214        self,
5215        functions: t.Optional[t.Dict[str, t.Callable]] = None,
5216        anonymous: bool = False,
5217        optional_parens: bool = True,
5218        any_token: bool = False,
5219    ) -> t.Optional[exp.Expression]:
5220        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
5221        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
5222        fn_syntax = False
5223        if (
5224            self._match(TokenType.L_BRACE, advance=False)
5225            and self._next
5226            and self._next.text.upper() == "FN"
5227        ):
5228            self._advance(2)
5229            fn_syntax = True
5230
5231        func = self._parse_function_call(
5232            functions=functions,
5233            anonymous=anonymous,
5234            optional_parens=optional_parens,
5235            any_token=any_token,
5236        )
5237
5238        if fn_syntax:
5239            self._match(TokenType.R_BRACE)
5240
5241        return func
5242
5243    def _parse_function_call(
5244        self,
5245        functions: t.Optional[t.Dict[str, t.Callable]] = None,
5246        anonymous: bool = False,
5247        optional_parens: bool = True,
5248        any_token: bool = False,
5249    ) -> t.Optional[exp.Expression]:
5250        if not self._curr:
5251            return None
5252
5253        comments = self._curr.comments
5254        token_type = self._curr.token_type
5255        this = self._curr.text
5256        upper = this.upper()
5257
5258        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
5259        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
5260            self._advance()
5261            return self._parse_window(parser(self))
5262
5263        if not self._next or self._next.token_type != TokenType.L_PAREN:
5264            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
5265                self._advance()
5266                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
5267
5268            return None
5269
5270        if any_token:
5271            if token_type in self.RESERVED_TOKENS:
5272                return None
5273        elif token_type not in self.FUNC_TOKENS:
5274            return None
5275
5276        self._advance(2)
5277
5278        parser = self.FUNCTION_PARSERS.get(upper)
5279        if parser and not anonymous:
5280            this = parser(self)
5281        else:
5282            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
5283
5284            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
5285                this = self.expression(
5286                    subquery_predicate, comments=comments, this=self._parse_select()
5287                )
5288                self._match_r_paren()
5289                return this
5290
5291            if functions is None:
5292                functions = self.FUNCTIONS
5293
5294            function = functions.get(upper)
5295
5296            alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS
5297            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
5298
5299            if alias:
5300                args = self._kv_to_prop_eq(args)
5301
5302            if function and not anonymous:
5303                if "dialect" in function.__code__.co_varnames:
5304                    func = function(args, dialect=self.dialect)
5305                else:
5306                    func = function(args)
5307
5308                func = self.validate_expression(func, args)
5309                if not self.dialect.NORMALIZE_FUNCTIONS:
5310                    func.meta["name"] = this
5311
5312                this = func
5313            else:
5314                if token_type == TokenType.IDENTIFIER:
5315                    this = exp.Identifier(this=this, quoted=True)
5316                this = self.expression(exp.Anonymous, this=this, expressions=args)
5317
5318        if isinstance(this, exp.Expression):
5319            this.add_comments(comments)
5320
5321        self._match_r_paren(this)
5322        return self._parse_window(this)
5323
5324    def _to_prop_eq(self, expression: exp.Expression, index: int) -> exp.Expression:
5325        return expression
5326
5327    def _kv_to_prop_eq(self, expressions: t.List[exp.Expression]) -> t.List[exp.Expression]:
5328        transformed = []
5329
5330        for index, e in enumerate(expressions):
5331            if isinstance(e, self.KEY_VALUE_DEFINITIONS):
5332                if isinstance(e, exp.Alias):
5333                    e = self.expression(exp.PropertyEQ, this=e.args.get("alias"), expression=e.this)
5334
5335                if not isinstance(e, exp.PropertyEQ):
5336                    e = self.expression(
5337                        exp.PropertyEQ, this=exp.to_identifier(e.this.name), expression=e.expression
5338                    )
5339
5340                if isinstance(e.this, exp.Column):
5341                    e.this.replace(e.this.this)
5342            else:
5343                e = self._to_prop_eq(e, index)
5344
5345            transformed.append(e)
5346
5347        return transformed
5348
5349    def _parse_user_defined_function_expression(self) -> t.Optional[exp.Expression]:
5350        return self._parse_statement()
5351
5352    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
5353        return self._parse_column_def(self._parse_id_var())
5354
5355    def _parse_user_defined_function(
5356        self, kind: t.Optional[TokenType] = None
5357    ) -> t.Optional[exp.Expression]:
5358        this = self._parse_id_var()
5359
5360        while self._match(TokenType.DOT):
5361            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
5362
5363        if not self._match(TokenType.L_PAREN):
5364            return this
5365
5366        expressions = self._parse_csv(self._parse_function_parameter)
5367        self._match_r_paren()
5368        return self.expression(
5369            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
5370        )
5371
5372    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
5373        literal = self._parse_primary()
5374        if literal:
5375            return self.expression(exp.Introducer, this=token.text, expression=literal)
5376
5377        return self.expression(exp.Identifier, this=token.text)
5378
5379    def _parse_session_parameter(self) -> exp.SessionParameter:
5380        kind = None
5381        this = self._parse_id_var() or self._parse_primary()
5382
5383        if this and self._match(TokenType.DOT):
5384            kind = this.name
5385            this = self._parse_var() or self._parse_primary()
5386
5387        return self.expression(exp.SessionParameter, this=this, kind=kind)
5388
5389    def _parse_lambda_arg(self) -> t.Optional[exp.Expression]:
5390        return self._parse_id_var()
5391
5392    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
5393        index = self._index
5394
5395        if self._match(TokenType.L_PAREN):
5396            expressions = t.cast(
5397                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_lambda_arg)
5398            )
5399
5400            if not self._match(TokenType.R_PAREN):
5401                self._retreat(index)
5402        else:
5403            expressions = [self._parse_lambda_arg()]
5404
5405        if self._match_set(self.LAMBDAS):
5406            return self.LAMBDAS[self._prev.token_type](self, expressions)
5407
5408        self._retreat(index)
5409
5410        this: t.Optional[exp.Expression]
5411
5412        if self._match(TokenType.DISTINCT):
5413            this = self.expression(
5414                exp.Distinct, expressions=self._parse_csv(self._parse_assignment)
5415            )
5416        else:
5417            this = self._parse_select_or_expression(alias=alias)
5418
5419        return self._parse_limit(
5420            self._parse_order(self._parse_having_max(self._parse_respect_or_ignore_nulls(this)))
5421        )
5422
5423    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
5424        index = self._index
5425        if not self._match(TokenType.L_PAREN):
5426            return this
5427
5428        # Disambiguate between schema and subquery/CTE, e.g. in INSERT INTO table (<expr>),
5429        # expr can be of both types
5430        if self._match_set(self.SELECT_START_TOKENS):
5431            self._retreat(index)
5432            return this
5433        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
5434        self._match_r_paren()
5435        return self.expression(exp.Schema, this=this, expressions=args)
5436
5437    def _parse_field_def(self) -> t.Optional[exp.Expression]:
5438        return self._parse_column_def(self._parse_field(any_token=True))
5439
5440    def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5441        # column defs are not really columns, they're identifiers
5442        if isinstance(this, exp.Column):
5443            this = this.this
5444
5445        kind = self._parse_types(schema=True)
5446
5447        if self._match_text_seq("FOR", "ORDINALITY"):
5448            return self.expression(exp.ColumnDef, this=this, ordinality=True)
5449
5450        constraints: t.List[exp.Expression] = []
5451
5452        if (not kind and self._match(TokenType.ALIAS)) or self._match_texts(
5453            ("ALIAS", "MATERIALIZED")
5454        ):
5455            persisted = self._prev.text.upper() == "MATERIALIZED"
5456            constraint_kind = exp.ComputedColumnConstraint(
5457                this=self._parse_assignment(),
5458                persisted=persisted or self._match_text_seq("PERSISTED"),
5459                not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
5460            )
5461            constraints.append(self.expression(exp.ColumnConstraint, kind=constraint_kind))
5462        elif kind and self._match_pair(TokenType.ALIAS, TokenType.L_PAREN, advance=False):
5463            self._match(TokenType.ALIAS)
5464            constraints.append(
5465                self.expression(
5466                    exp.ColumnConstraint,
5467                    kind=exp.TransformColumnConstraint(this=self._parse_field()),
5468                )
5469            )
5470
5471        while True:
5472            constraint = self._parse_column_constraint()
5473            if not constraint:
5474                break
5475            constraints.append(constraint)
5476
5477        if not kind and not constraints:
5478            return this
5479
5480        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
5481
5482    def _parse_auto_increment(
5483        self,
5484    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
5485        start = None
5486        increment = None
5487
5488        if self._match(TokenType.L_PAREN, advance=False):
5489            args = self._parse_wrapped_csv(self._parse_bitwise)
5490            start = seq_get(args, 0)
5491            increment = seq_get(args, 1)
5492        elif self._match_text_seq("START"):
5493            start = self._parse_bitwise()
5494            self._match_text_seq("INCREMENT")
5495            increment = self._parse_bitwise()
5496
5497        if start and increment:
5498            return exp.GeneratedAsIdentityColumnConstraint(start=start, increment=increment)
5499
5500        return exp.AutoIncrementColumnConstraint()
5501
5502    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
5503        if not self._match_text_seq("REFRESH"):
5504            self._retreat(self._index - 1)
5505            return None
5506        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
5507
5508    def _parse_compress(self) -> exp.CompressColumnConstraint:
5509        if self._match(TokenType.L_PAREN, advance=False):
5510            return self.expression(
5511                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
5512            )
5513
5514        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
5515
5516    def _parse_generated_as_identity(
5517        self,
5518    ) -> (
5519        exp.GeneratedAsIdentityColumnConstraint
5520        | exp.ComputedColumnConstraint
5521        | exp.GeneratedAsRowColumnConstraint
5522    ):
5523        if self._match_text_seq("BY", "DEFAULT"):
5524            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
5525            this = self.expression(
5526                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
5527            )
5528        else:
5529            self._match_text_seq("ALWAYS")
5530            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
5531
5532        self._match(TokenType.ALIAS)
5533
5534        if self._match_text_seq("ROW"):
5535            start = self._match_text_seq("START")
5536            if not start:
5537                self._match(TokenType.END)
5538            hidden = self._match_text_seq("HIDDEN")
5539            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
5540
5541        identity = self._match_text_seq("IDENTITY")
5542
5543        if self._match(TokenType.L_PAREN):
5544            if self._match(TokenType.START_WITH):
5545                this.set("start", self._parse_bitwise())
5546            if self._match_text_seq("INCREMENT", "BY"):
5547                this.set("increment", self._parse_bitwise())
5548            if self._match_text_seq("MINVALUE"):
5549                this.set("minvalue", self._parse_bitwise())
5550            if self._match_text_seq("MAXVALUE"):
5551                this.set("maxvalue", self._parse_bitwise())
5552
5553            if self._match_text_seq("CYCLE"):
5554                this.set("cycle", True)
5555            elif self._match_text_seq("NO", "CYCLE"):
5556                this.set("cycle", False)
5557
5558            if not identity:
5559                this.set("expression", self._parse_range())
5560            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
5561                args = self._parse_csv(self._parse_bitwise)
5562                this.set("start", seq_get(args, 0))
5563                this.set("increment", seq_get(args, 1))
5564
5565            self._match_r_paren()
5566
5567        return this
5568
5569    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
5570        self._match_text_seq("LENGTH")
5571        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
5572
5573    def _parse_not_constraint(self) -> t.Optional[exp.Expression]:
5574        if self._match_text_seq("NULL"):
5575            return self.expression(exp.NotNullColumnConstraint)
5576        if self._match_text_seq("CASESPECIFIC"):
5577            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
5578        if self._match_text_seq("FOR", "REPLICATION"):
5579            return self.expression(exp.NotForReplicationColumnConstraint)
5580
5581        # Unconsume the `NOT` token
5582        self._retreat(self._index - 1)
5583        return None
5584
5585    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
5586        this = self._match(TokenType.CONSTRAINT) and self._parse_id_var()
5587
5588        procedure_option_follows = (
5589            self._match(TokenType.WITH, advance=False)
5590            and self._next
5591            and self._next.text.upper() in self.PROCEDURE_OPTIONS
5592        )
5593
5594        if not procedure_option_follows and self._match_texts(self.CONSTRAINT_PARSERS):
5595            return self.expression(
5596                exp.ColumnConstraint,
5597                this=this,
5598                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
5599            )
5600
5601        return this
5602
5603    def _parse_constraint(self) -> t.Optional[exp.Expression]:
5604        if not self._match(TokenType.CONSTRAINT):
5605            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
5606
5607        return self.expression(
5608            exp.Constraint,
5609            this=self._parse_id_var(),
5610            expressions=self._parse_unnamed_constraints(),
5611        )
5612
5613    def _parse_unnamed_constraints(self) -> t.List[exp.Expression]:
5614        constraints = []
5615        while True:
5616            constraint = self._parse_unnamed_constraint() or self._parse_function()
5617            if not constraint:
5618                break
5619            constraints.append(constraint)
5620
5621        return constraints
5622
5623    def _parse_unnamed_constraint(
5624        self, constraints: t.Optional[t.Collection[str]] = None
5625    ) -> t.Optional[exp.Expression]:
5626        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
5627            constraints or self.CONSTRAINT_PARSERS
5628        ):
5629            return None
5630
5631        constraint = self._prev.text.upper()
5632        if constraint not in self.CONSTRAINT_PARSERS:
5633            self.raise_error(f"No parser found for schema constraint {constraint}.")
5634
5635        return self.CONSTRAINT_PARSERS[constraint](self)
5636
5637    def _parse_unique_key(self) -> t.Optional[exp.Expression]:
5638        return self._parse_id_var(any_token=False)
5639
5640    def _parse_unique(self) -> exp.UniqueColumnConstraint:
5641        self._match_text_seq("KEY")
5642        return self.expression(
5643            exp.UniqueColumnConstraint,
5644            nulls=self._match_text_seq("NULLS", "NOT", "DISTINCT"),
5645            this=self._parse_schema(self._parse_unique_key()),
5646            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
5647            on_conflict=self._parse_on_conflict(),
5648        )
5649
5650    def _parse_key_constraint_options(self) -> t.List[str]:
5651        options = []
5652        while True:
5653            if not self._curr:
5654                break
5655
5656            if self._match(TokenType.ON):
5657                action = None
5658                on = self._advance_any() and self._prev.text
5659
5660                if self._match_text_seq("NO", "ACTION"):
5661                    action = "NO ACTION"
5662                elif self._match_text_seq("CASCADE"):
5663                    action = "CASCADE"
5664                elif self._match_text_seq("RESTRICT"):
5665                    action = "RESTRICT"
5666                elif self._match_pair(TokenType.SET, TokenType.NULL):
5667                    action = "SET NULL"
5668                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
5669                    action = "SET DEFAULT"
5670                else:
5671                    self.raise_error("Invalid key constraint")
5672
5673                options.append(f"ON {on} {action}")
5674            else:
5675                var = self._parse_var_from_options(
5676                    self.KEY_CONSTRAINT_OPTIONS, raise_unmatched=False
5677                )
5678                if not var:
5679                    break
5680                options.append(var.name)
5681
5682        return options
5683
5684    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
5685        if match and not self._match(TokenType.REFERENCES):
5686            return None
5687
5688        expressions = None
5689        this = self._parse_table(schema=True)
5690        options = self._parse_key_constraint_options()
5691        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
5692
5693    def _parse_foreign_key(self) -> exp.ForeignKey:
5694        expressions = self._parse_wrapped_id_vars()
5695        reference = self._parse_references()
5696        options = {}
5697
5698        while self._match(TokenType.ON):
5699            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
5700                self.raise_error("Expected DELETE or UPDATE")
5701
5702            kind = self._prev.text.lower()
5703
5704            if self._match_text_seq("NO", "ACTION"):
5705                action = "NO ACTION"
5706            elif self._match(TokenType.SET):
5707                self._match_set((TokenType.NULL, TokenType.DEFAULT))
5708                action = "SET " + self._prev.text.upper()
5709            else:
5710                self._advance()
5711                action = self._prev.text.upper()
5712
5713            options[kind] = action
5714
5715        return self.expression(
5716            exp.ForeignKey,
5717            expressions=expressions,
5718            reference=reference,
5719            **options,  # type: ignore
5720        )
5721
5722    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
5723        return self._parse_field()
5724
5725    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
5726        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
5727            self._retreat(self._index - 1)
5728            return None
5729
5730        id_vars = self._parse_wrapped_id_vars()
5731        return self.expression(
5732            exp.PeriodForSystemTimeConstraint,
5733            this=seq_get(id_vars, 0),
5734            expression=seq_get(id_vars, 1),
5735        )
5736
5737    def _parse_primary_key(
5738        self, wrapped_optional: bool = False, in_props: bool = False
5739    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
5740        desc = (
5741            self._match_set((TokenType.ASC, TokenType.DESC))
5742            and self._prev.token_type == TokenType.DESC
5743        )
5744
5745        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
5746            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
5747
5748        expressions = self._parse_wrapped_csv(
5749            self._parse_primary_key_part, optional=wrapped_optional
5750        )
5751        options = self._parse_key_constraint_options()
5752        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
5753
5754    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
5755        return self._parse_slice(self._parse_alias(self._parse_assignment(), explicit=True))
5756
5757    def _parse_odbc_datetime_literal(self) -> exp.Expression:
5758        """
5759        Parses a datetime column in ODBC format. We parse the column into the corresponding
5760        types, for example `{d'yyyy-mm-dd'}` will be parsed as a `Date` column, exactly the
5761        same as we did for `DATE('yyyy-mm-dd')`.
5762
5763        Reference:
5764        https://learn.microsoft.com/en-us/sql/odbc/reference/develop-app/date-time-and-timestamp-literals
5765        """
5766        self._match(TokenType.VAR)
5767        exp_class = self.ODBC_DATETIME_LITERALS[self._prev.text.lower()]
5768        expression = self.expression(exp_class=exp_class, this=self._parse_string())
5769        if not self._match(TokenType.R_BRACE):
5770            self.raise_error("Expected }")
5771        return expression
5772
5773    def _parse_bracket(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
5774        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
5775            return this
5776
5777        bracket_kind = self._prev.token_type
5778        if (
5779            bracket_kind == TokenType.L_BRACE
5780            and self._curr
5781            and self._curr.token_type == TokenType.VAR
5782            and self._curr.text.lower() in self.ODBC_DATETIME_LITERALS
5783        ):
5784            return self._parse_odbc_datetime_literal()
5785
5786        expressions = self._parse_csv(
5787            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
5788        )
5789
5790        if bracket_kind == TokenType.L_BRACKET and not self._match(TokenType.R_BRACKET):
5791            self.raise_error("Expected ]")
5792        elif bracket_kind == TokenType.L_BRACE and not self._match(TokenType.R_BRACE):
5793            self.raise_error("Expected }")
5794
5795        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
5796        if bracket_kind == TokenType.L_BRACE:
5797            this = self.expression(exp.Struct, expressions=self._kv_to_prop_eq(expressions))
5798        elif not this:
5799            this = build_array_constructor(
5800                exp.Array, args=expressions, bracket_kind=bracket_kind, dialect=self.dialect
5801            )
5802        else:
5803            constructor_type = self.ARRAY_CONSTRUCTORS.get(this.name.upper())
5804            if constructor_type:
5805                return build_array_constructor(
5806                    constructor_type,
5807                    args=expressions,
5808                    bracket_kind=bracket_kind,
5809                    dialect=self.dialect,
5810                )
5811
5812            expressions = apply_index_offset(this, expressions, -self.dialect.INDEX_OFFSET)
5813            this = self.expression(exp.Bracket, this=this, expressions=expressions)
5814
5815        self._add_comments(this)
5816        return self._parse_bracket(this)
5817
5818    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5819        if self._match(TokenType.COLON):
5820            return self.expression(exp.Slice, this=this, expression=self._parse_assignment())
5821        return this
5822
5823    def _parse_case(self) -> t.Optional[exp.Expression]:
5824        ifs = []
5825        default = None
5826
5827        comments = self._prev_comments
5828        expression = self._parse_assignment()
5829
5830        while self._match(TokenType.WHEN):
5831            this = self._parse_assignment()
5832            self._match(TokenType.THEN)
5833            then = self._parse_assignment()
5834            ifs.append(self.expression(exp.If, this=this, true=then))
5835
5836        if self._match(TokenType.ELSE):
5837            default = self._parse_assignment()
5838
5839        if not self._match(TokenType.END):
5840            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
5841                default = exp.column("interval")
5842            else:
5843                self.raise_error("Expected END after CASE", self._prev)
5844
5845        return self.expression(
5846            exp.Case, comments=comments, this=expression, ifs=ifs, default=default
5847        )
5848
5849    def _parse_if(self) -> t.Optional[exp.Expression]:
5850        if self._match(TokenType.L_PAREN):
5851            args = self._parse_csv(self._parse_assignment)
5852            this = self.validate_expression(exp.If.from_arg_list(args), args)
5853            self._match_r_paren()
5854        else:
5855            index = self._index - 1
5856
5857            if self.NO_PAREN_IF_COMMANDS and index == 0:
5858                return self._parse_as_command(self._prev)
5859
5860            condition = self._parse_assignment()
5861
5862            if not condition:
5863                self._retreat(index)
5864                return None
5865
5866            self._match(TokenType.THEN)
5867            true = self._parse_assignment()
5868            false = self._parse_assignment() if self._match(TokenType.ELSE) else None
5869            self._match(TokenType.END)
5870            this = self.expression(exp.If, this=condition, true=true, false=false)
5871
5872        return this
5873
5874    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
5875        if not self._match_text_seq("VALUE", "FOR"):
5876            self._retreat(self._index - 1)
5877            return None
5878
5879        return self.expression(
5880            exp.NextValueFor,
5881            this=self._parse_column(),
5882            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
5883        )
5884
5885    def _parse_extract(self) -> exp.Extract | exp.Anonymous:
5886        this = self._parse_function() or self._parse_var_or_string(upper=True)
5887
5888        if self._match(TokenType.FROM):
5889            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
5890
5891        if not self._match(TokenType.COMMA):
5892            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
5893
5894        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
5895
5896    def _parse_gap_fill(self) -> exp.GapFill:
5897        self._match(TokenType.TABLE)
5898        this = self._parse_table()
5899
5900        self._match(TokenType.COMMA)
5901        args = [this, *self._parse_csv(self._parse_lambda)]
5902
5903        gap_fill = exp.GapFill.from_arg_list(args)
5904        return self.validate_expression(gap_fill, args)
5905
5906    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
5907        this = self._parse_assignment()
5908
5909        if not self._match(TokenType.ALIAS):
5910            if self._match(TokenType.COMMA):
5911                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
5912
5913            self.raise_error("Expected AS after CAST")
5914
5915        fmt = None
5916        to = self._parse_types()
5917
5918        if self._match(TokenType.FORMAT):
5919            fmt_string = self._parse_string()
5920            fmt = self._parse_at_time_zone(fmt_string)
5921
5922            if not to:
5923                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
5924            if to.this in exp.DataType.TEMPORAL_TYPES:
5925                this = self.expression(
5926                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
5927                    this=this,
5928                    format=exp.Literal.string(
5929                        format_time(
5930                            fmt_string.this if fmt_string else "",
5931                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
5932                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
5933                        )
5934                    ),
5935                    safe=safe,
5936                )
5937
5938                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
5939                    this.set("zone", fmt.args["zone"])
5940                return this
5941        elif not to:
5942            self.raise_error("Expected TYPE after CAST")
5943        elif isinstance(to, exp.Identifier):
5944            to = exp.DataType.build(to.name, udt=True)
5945        elif to.this == exp.DataType.Type.CHAR:
5946            if self._match(TokenType.CHARACTER_SET):
5947                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
5948
5949        return self.expression(
5950            exp.Cast if strict else exp.TryCast,
5951            this=this,
5952            to=to,
5953            format=fmt,
5954            safe=safe,
5955            action=self._parse_var_from_options(self.CAST_ACTIONS, raise_unmatched=False),
5956        )
5957
5958    def _parse_string_agg(self) -> exp.GroupConcat:
5959        if self._match(TokenType.DISTINCT):
5960            args: t.List[t.Optional[exp.Expression]] = [
5961                self.expression(exp.Distinct, expressions=[self._parse_assignment()])
5962            ]
5963            if self._match(TokenType.COMMA):
5964                args.extend(self._parse_csv(self._parse_assignment))
5965        else:
5966            args = self._parse_csv(self._parse_assignment)  # type: ignore
5967
5968        if self._match_text_seq("ON", "OVERFLOW"):
5969            # trino: LISTAGG(expression [, separator] [ON OVERFLOW overflow_behavior])
5970            if self._match_text_seq("ERROR"):
5971                on_overflow: t.Optional[exp.Expression] = exp.var("ERROR")
5972            else:
5973                self._match_text_seq("TRUNCATE")
5974                on_overflow = self.expression(
5975                    exp.OverflowTruncateBehavior,
5976                    this=self._parse_string(),
5977                    with_count=(
5978                        self._match_text_seq("WITH", "COUNT")
5979                        or not self._match_text_seq("WITHOUT", "COUNT")
5980                    ),
5981                )
5982        else:
5983            on_overflow = None
5984
5985        index = self._index
5986        if not self._match(TokenType.R_PAREN) and args:
5987            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
5988            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
5989            args[-1] = self._parse_limit(this=self._parse_order(this=args[-1]))
5990            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
5991
5992        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
5993        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
5994        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
5995        if not self._match_text_seq("WITHIN", "GROUP"):
5996            self._retreat(index)
5997            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
5998
5999        # The corresponding match_r_paren will be called in parse_function (caller)
6000        self._match_l_paren()
6001
6002        return self.expression(
6003            exp.GroupConcat,
6004            this=self._parse_order(this=seq_get(args, 0)),
6005            separator=seq_get(args, 1),
6006            on_overflow=on_overflow,
6007        )
6008
6009    def _parse_convert(
6010        self, strict: bool, safe: t.Optional[bool] = None
6011    ) -> t.Optional[exp.Expression]:
6012        this = self._parse_bitwise()
6013
6014        if self._match(TokenType.USING):
6015            to: t.Optional[exp.Expression] = self.expression(
6016                exp.CharacterSet, this=self._parse_var()
6017            )
6018        elif self._match(TokenType.COMMA):
6019            to = self._parse_types()
6020        else:
6021            to = None
6022
6023        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
6024
6025    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
6026        """
6027        There are generally two variants of the DECODE function:
6028
6029        - DECODE(bin, charset)
6030        - DECODE(expression, search, result [, search, result] ... [, default])
6031
6032        The second variant will always be parsed into a CASE expression. Note that NULL
6033        needs special treatment, since we need to explicitly check for it with `IS NULL`,
6034        instead of relying on pattern matching.
6035        """
6036        args = self._parse_csv(self._parse_assignment)
6037
6038        if len(args) < 3:
6039            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
6040
6041        expression, *expressions = args
6042        if not expression:
6043            return None
6044
6045        ifs = []
6046        for search, result in zip(expressions[::2], expressions[1::2]):
6047            if not search or not result:
6048                return None
6049
6050            if isinstance(search, exp.Literal):
6051                ifs.append(
6052                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
6053                )
6054            elif isinstance(search, exp.Null):
6055                ifs.append(
6056                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
6057                )
6058            else:
6059                cond = exp.or_(
6060                    exp.EQ(this=expression.copy(), expression=search),
6061                    exp.and_(
6062                        exp.Is(this=expression.copy(), expression=exp.Null()),
6063                        exp.Is(this=search.copy(), expression=exp.Null()),
6064                        copy=False,
6065                    ),
6066                    copy=False,
6067                )
6068                ifs.append(exp.If(this=cond, true=result))
6069
6070        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
6071
6072    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
6073        self._match_text_seq("KEY")
6074        key = self._parse_column()
6075        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
6076        self._match_text_seq("VALUE")
6077        value = self._parse_bitwise()
6078
6079        if not key and not value:
6080            return None
6081        return self.expression(exp.JSONKeyValue, this=key, expression=value)
6082
6083    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
6084        if not this or not self._match_text_seq("FORMAT", "JSON"):
6085            return this
6086
6087        return self.expression(exp.FormatJson, this=this)
6088
6089    def _parse_on_condition(self) -> t.Optional[exp.OnCondition]:
6090        # MySQL uses "X ON EMPTY Y ON ERROR" (e.g. JSON_VALUE) while Oracle uses the opposite (e.g. JSON_EXISTS)
6091        if self.dialect.ON_CONDITION_EMPTY_BEFORE_ERROR:
6092            empty = self._parse_on_handling("EMPTY", *self.ON_CONDITION_TOKENS)
6093            error = self._parse_on_handling("ERROR", *self.ON_CONDITION_TOKENS)
6094        else:
6095            error = self._parse_on_handling("ERROR", *self.ON_CONDITION_TOKENS)
6096            empty = self._parse_on_handling("EMPTY", *self.ON_CONDITION_TOKENS)
6097
6098        null = self._parse_on_handling("NULL", *self.ON_CONDITION_TOKENS)
6099
6100        if not empty and not error and not null:
6101            return None
6102
6103        return self.expression(
6104            exp.OnCondition,
6105            empty=empty,
6106            error=error,
6107            null=null,
6108        )
6109
6110    def _parse_on_handling(
6111        self, on: str, *values: str
6112    ) -> t.Optional[str] | t.Optional[exp.Expression]:
6113        # Parses the "X ON Y" or "DEFAULT <expr> ON Y syntax, e.g. NULL ON NULL (Oracle, T-SQL, MySQL)
6114        for value in values:
6115            if self._match_text_seq(value, "ON", on):
6116                return f"{value} ON {on}"
6117
6118        index = self._index
6119        if self._match(TokenType.DEFAULT):
6120            default_value = self._parse_bitwise()
6121            if self._match_text_seq("ON", on):
6122                return default_value
6123
6124            self._retreat(index)
6125
6126        return None
6127
6128    @t.overload
6129    def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
6130
6131    @t.overload
6132    def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
6133
6134    def _parse_json_object(self, agg=False):
6135        star = self._parse_star()
6136        expressions = (
6137            [star]
6138            if star
6139            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
6140        )
6141        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
6142
6143        unique_keys = None
6144        if self._match_text_seq("WITH", "UNIQUE"):
6145            unique_keys = True
6146        elif self._match_text_seq("WITHOUT", "UNIQUE"):
6147            unique_keys = False
6148
6149        self._match_text_seq("KEYS")
6150
6151        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
6152            self._parse_type()
6153        )
6154        encoding = self._match_text_seq("ENCODING") and self._parse_var()
6155
6156        return self.expression(
6157            exp.JSONObjectAgg if agg else exp.JSONObject,
6158            expressions=expressions,
6159            null_handling=null_handling,
6160            unique_keys=unique_keys,
6161            return_type=return_type,
6162            encoding=encoding,
6163        )
6164
6165    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
6166    def _parse_json_column_def(self) -> exp.JSONColumnDef:
6167        if not self._match_text_seq("NESTED"):
6168            this = self._parse_id_var()
6169            kind = self._parse_types(allow_identifiers=False)
6170            nested = None
6171        else:
6172            this = None
6173            kind = None
6174            nested = True
6175
6176        path = self._match_text_seq("PATH") and self._parse_string()
6177        nested_schema = nested and self._parse_json_schema()
6178
6179        return self.expression(
6180            exp.JSONColumnDef,
6181            this=this,
6182            kind=kind,
6183            path=path,
6184            nested_schema=nested_schema,
6185        )
6186
6187    def _parse_json_schema(self) -> exp.JSONSchema:
6188        self._match_text_seq("COLUMNS")
6189        return self.expression(
6190            exp.JSONSchema,
6191            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
6192        )
6193
6194    def _parse_json_table(self) -> exp.JSONTable:
6195        this = self._parse_format_json(self._parse_bitwise())
6196        path = self._match(TokenType.COMMA) and self._parse_string()
6197        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
6198        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
6199        schema = self._parse_json_schema()
6200
6201        return exp.JSONTable(
6202            this=this,
6203            schema=schema,
6204            path=path,
6205            error_handling=error_handling,
6206            empty_handling=empty_handling,
6207        )
6208
6209    def _parse_match_against(self) -> exp.MatchAgainst:
6210        expressions = self._parse_csv(self._parse_column)
6211
6212        self._match_text_seq(")", "AGAINST", "(")
6213
6214        this = self._parse_string()
6215
6216        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
6217            modifier = "IN NATURAL LANGUAGE MODE"
6218            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
6219                modifier = f"{modifier} WITH QUERY EXPANSION"
6220        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
6221            modifier = "IN BOOLEAN MODE"
6222        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
6223            modifier = "WITH QUERY EXPANSION"
6224        else:
6225            modifier = None
6226
6227        return self.expression(
6228            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
6229        )
6230
6231    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
6232    def _parse_open_json(self) -> exp.OpenJSON:
6233        this = self._parse_bitwise()
6234        path = self._match(TokenType.COMMA) and self._parse_string()
6235
6236        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
6237            this = self._parse_field(any_token=True)
6238            kind = self._parse_types()
6239            path = self._parse_string()
6240            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
6241
6242            return self.expression(
6243                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
6244            )
6245
6246        expressions = None
6247        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
6248            self._match_l_paren()
6249            expressions = self._parse_csv(_parse_open_json_column_def)
6250
6251        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
6252
6253    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
6254        args = self._parse_csv(self._parse_bitwise)
6255
6256        if self._match(TokenType.IN):
6257            return self.expression(
6258                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
6259            )
6260
6261        if haystack_first:
6262            haystack = seq_get(args, 0)
6263            needle = seq_get(args, 1)
6264        else:
6265            needle = seq_get(args, 0)
6266            haystack = seq_get(args, 1)
6267
6268        return self.expression(
6269            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
6270        )
6271
6272    def _parse_predict(self) -> exp.Predict:
6273        self._match_text_seq("MODEL")
6274        this = self._parse_table()
6275
6276        self._match(TokenType.COMMA)
6277        self._match_text_seq("TABLE")
6278
6279        return self.expression(
6280            exp.Predict,
6281            this=this,
6282            expression=self._parse_table(),
6283            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
6284        )
6285
6286    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
6287        args = self._parse_csv(self._parse_table)
6288        return exp.JoinHint(this=func_name.upper(), expressions=args)
6289
6290    def _parse_substring(self) -> exp.Substring:
6291        # Postgres supports the form: substring(string [from int] [for int])
6292        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
6293
6294        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
6295
6296        if self._match(TokenType.FROM):
6297            args.append(self._parse_bitwise())
6298        if self._match(TokenType.FOR):
6299            if len(args) == 1:
6300                args.append(exp.Literal.number(1))
6301            args.append(self._parse_bitwise())
6302
6303        return self.validate_expression(exp.Substring.from_arg_list(args), args)
6304
6305    def _parse_trim(self) -> exp.Trim:
6306        # https://www.w3resource.com/sql/character-functions/trim.php
6307        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
6308
6309        position = None
6310        collation = None
6311        expression = None
6312
6313        if self._match_texts(self.TRIM_TYPES):
6314            position = self._prev.text.upper()
6315
6316        this = self._parse_bitwise()
6317        if self._match_set((TokenType.FROM, TokenType.COMMA)):
6318            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
6319            expression = self._parse_bitwise()
6320
6321            if invert_order:
6322                this, expression = expression, this
6323
6324        if self._match(TokenType.COLLATE):
6325            collation = self._parse_bitwise()
6326
6327        return self.expression(
6328            exp.Trim, this=this, position=position, expression=expression, collation=collation
6329        )
6330
6331    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
6332        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
6333
6334    def _parse_named_window(self) -> t.Optional[exp.Expression]:
6335        return self._parse_window(self._parse_id_var(), alias=True)
6336
6337    def _parse_respect_or_ignore_nulls(
6338        self, this: t.Optional[exp.Expression]
6339    ) -> t.Optional[exp.Expression]:
6340        if self._match_text_seq("IGNORE", "NULLS"):
6341            return self.expression(exp.IgnoreNulls, this=this)
6342        if self._match_text_seq("RESPECT", "NULLS"):
6343            return self.expression(exp.RespectNulls, this=this)
6344        return this
6345
6346    def _parse_having_max(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
6347        if self._match(TokenType.HAVING):
6348            self._match_texts(("MAX", "MIN"))
6349            max = self._prev.text.upper() != "MIN"
6350            return self.expression(
6351                exp.HavingMax, this=this, expression=self._parse_column(), max=max
6352            )
6353
6354        return this
6355
6356    def _parse_window(
6357        self, this: t.Optional[exp.Expression], alias: bool = False
6358    ) -> t.Optional[exp.Expression]:
6359        func = this
6360        comments = func.comments if isinstance(func, exp.Expression) else None
6361
6362        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
6363            self._match(TokenType.WHERE)
6364            this = self.expression(
6365                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
6366            )
6367            self._match_r_paren()
6368
6369        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
6370        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
6371        if self._match_text_seq("WITHIN", "GROUP"):
6372            order = self._parse_wrapped(self._parse_order)
6373            this = self.expression(exp.WithinGroup, this=this, expression=order)
6374
6375        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
6376        # Some dialects choose to implement and some do not.
6377        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
6378
6379        # There is some code above in _parse_lambda that handles
6380        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
6381
6382        # The below changes handle
6383        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
6384
6385        # Oracle allows both formats
6386        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
6387        #   and Snowflake chose to do the same for familiarity
6388        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
6389        if isinstance(this, exp.AggFunc):
6390            ignore_respect = this.find(exp.IgnoreNulls, exp.RespectNulls)
6391
6392            if ignore_respect and ignore_respect is not this:
6393                ignore_respect.replace(ignore_respect.this)
6394                this = self.expression(ignore_respect.__class__, this=this)
6395
6396        this = self._parse_respect_or_ignore_nulls(this)
6397
6398        # bigquery select from window x AS (partition by ...)
6399        if alias:
6400            over = None
6401            self._match(TokenType.ALIAS)
6402        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
6403            return this
6404        else:
6405            over = self._prev.text.upper()
6406
6407        if comments and isinstance(func, exp.Expression):
6408            func.pop_comments()
6409
6410        if not self._match(TokenType.L_PAREN):
6411            return self.expression(
6412                exp.Window,
6413                comments=comments,
6414                this=this,
6415                alias=self._parse_id_var(False),
6416                over=over,
6417            )
6418
6419        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
6420
6421        first = self._match(TokenType.FIRST)
6422        if self._match_text_seq("LAST"):
6423            first = False
6424
6425        partition, order = self._parse_partition_and_order()
6426        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
6427
6428        if kind:
6429            self._match(TokenType.BETWEEN)
6430            start = self._parse_window_spec()
6431            self._match(TokenType.AND)
6432            end = self._parse_window_spec()
6433
6434            spec = self.expression(
6435                exp.WindowSpec,
6436                kind=kind,
6437                start=start["value"],
6438                start_side=start["side"],
6439                end=end["value"],
6440                end_side=end["side"],
6441            )
6442        else:
6443            spec = None
6444
6445        self._match_r_paren()
6446
6447        window = self.expression(
6448            exp.Window,
6449            comments=comments,
6450            this=this,
6451            partition_by=partition,
6452            order=order,
6453            spec=spec,
6454            alias=window_alias,
6455            over=over,
6456            first=first,
6457        )
6458
6459        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
6460        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
6461            return self._parse_window(window, alias=alias)
6462
6463        return window
6464
6465    def _parse_partition_and_order(
6466        self,
6467    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
6468        return self._parse_partition_by(), self._parse_order()
6469
6470    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
6471        self._match(TokenType.BETWEEN)
6472
6473        return {
6474            "value": (
6475                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
6476                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
6477                or self._parse_bitwise()
6478            ),
6479            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
6480        }
6481
6482    def _parse_alias(
6483        self, this: t.Optional[exp.Expression], explicit: bool = False
6484    ) -> t.Optional[exp.Expression]:
6485        any_token = self._match(TokenType.ALIAS)
6486        comments = self._prev_comments or []
6487
6488        if explicit and not any_token:
6489            return this
6490
6491        if self._match(TokenType.L_PAREN):
6492            aliases = self.expression(
6493                exp.Aliases,
6494                comments=comments,
6495                this=this,
6496                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
6497            )
6498            self._match_r_paren(aliases)
6499            return aliases
6500
6501        alias = self._parse_id_var(any_token, tokens=self.ALIAS_TOKENS) or (
6502            self.STRING_ALIASES and self._parse_string_as_identifier()
6503        )
6504
6505        if alias:
6506            comments.extend(alias.pop_comments())
6507            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
6508            column = this.this
6509
6510            # Moves the comment next to the alias in `expr /* comment */ AS alias`
6511            if not this.comments and column and column.comments:
6512                this.comments = column.pop_comments()
6513
6514        return this
6515
6516    def _parse_id_var(
6517        self,
6518        any_token: bool = True,
6519        tokens: t.Optional[t.Collection[TokenType]] = None,
6520    ) -> t.Optional[exp.Expression]:
6521        expression = self._parse_identifier()
6522        if not expression and (
6523            (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS)
6524        ):
6525            quoted = self._prev.token_type == TokenType.STRING
6526            expression = self.expression(exp.Identifier, this=self._prev.text, quoted=quoted)
6527
6528        return expression
6529
6530    def _parse_string(self) -> t.Optional[exp.Expression]:
6531        if self._match_set(self.STRING_PARSERS):
6532            return self.STRING_PARSERS[self._prev.token_type](self, self._prev)
6533        return self._parse_placeholder()
6534
6535    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
6536        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
6537
6538    def _parse_number(self) -> t.Optional[exp.Expression]:
6539        if self._match_set(self.NUMERIC_PARSERS):
6540            return self.NUMERIC_PARSERS[self._prev.token_type](self, self._prev)
6541        return self._parse_placeholder()
6542
6543    def _parse_identifier(self) -> t.Optional[exp.Expression]:
6544        if self._match(TokenType.IDENTIFIER):
6545            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
6546        return self._parse_placeholder()
6547
6548    def _parse_var(
6549        self,
6550        any_token: bool = False,
6551        tokens: t.Optional[t.Collection[TokenType]] = None,
6552        upper: bool = False,
6553    ) -> t.Optional[exp.Expression]:
6554        if (
6555            (any_token and self._advance_any())
6556            or self._match(TokenType.VAR)
6557            or (self._match_set(tokens) if tokens else False)
6558        ):
6559            return self.expression(
6560                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
6561            )
6562        return self._parse_placeholder()
6563
6564    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
6565        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
6566            self._advance()
6567            return self._prev
6568        return None
6569
6570    def _parse_var_or_string(self, upper: bool = False) -> t.Optional[exp.Expression]:
6571        return self._parse_string() or self._parse_var(any_token=True, upper=upper)
6572
6573    def _parse_primary_or_var(self) -> t.Optional[exp.Expression]:
6574        return self._parse_primary() or self._parse_var(any_token=True)
6575
6576    def _parse_null(self) -> t.Optional[exp.Expression]:
6577        if self._match_set(self.NULL_TOKENS):
6578            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
6579        return self._parse_placeholder()
6580
6581    def _parse_boolean(self) -> t.Optional[exp.Expression]:
6582        if self._match(TokenType.TRUE):
6583            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
6584        if self._match(TokenType.FALSE):
6585            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
6586        return self._parse_placeholder()
6587
6588    def _parse_star(self) -> t.Optional[exp.Expression]:
6589        if self._match(TokenType.STAR):
6590            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
6591        return self._parse_placeholder()
6592
6593    def _parse_parameter(self) -> exp.Parameter:
6594        this = self._parse_identifier() or self._parse_primary_or_var()
6595        return self.expression(exp.Parameter, this=this)
6596
6597    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
6598        if self._match_set(self.PLACEHOLDER_PARSERS):
6599            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
6600            if placeholder:
6601                return placeholder
6602            self._advance(-1)
6603        return None
6604
6605    def _parse_star_op(self, *keywords: str) -> t.Optional[t.List[exp.Expression]]:
6606        if not self._match_texts(keywords):
6607            return None
6608        if self._match(TokenType.L_PAREN, advance=False):
6609            return self._parse_wrapped_csv(self._parse_expression)
6610
6611        expression = self._parse_expression()
6612        return [expression] if expression else None
6613
6614    def _parse_csv(
6615        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
6616    ) -> t.List[exp.Expression]:
6617        parse_result = parse_method()
6618        items = [parse_result] if parse_result is not None else []
6619
6620        while self._match(sep):
6621            self._add_comments(parse_result)
6622            parse_result = parse_method()
6623            if parse_result is not None:
6624                items.append(parse_result)
6625
6626        return items
6627
6628    def _parse_tokens(
6629        self, parse_method: t.Callable, expressions: t.Dict
6630    ) -> t.Optional[exp.Expression]:
6631        this = parse_method()
6632
6633        while self._match_set(expressions):
6634            this = self.expression(
6635                expressions[self._prev.token_type],
6636                this=this,
6637                comments=self._prev_comments,
6638                expression=parse_method(),
6639            )
6640
6641        return this
6642
6643    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
6644        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
6645
6646    def _parse_wrapped_csv(
6647        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
6648    ) -> t.List[exp.Expression]:
6649        return self._parse_wrapped(
6650            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
6651        )
6652
6653    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
6654        wrapped = self._match(TokenType.L_PAREN)
6655        if not wrapped and not optional:
6656            self.raise_error("Expecting (")
6657        parse_result = parse_method()
6658        if wrapped:
6659            self._match_r_paren()
6660        return parse_result
6661
6662    def _parse_expressions(self) -> t.List[exp.Expression]:
6663        return self._parse_csv(self._parse_expression)
6664
6665    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
6666        return self._parse_select() or self._parse_set_operations(
6667            self._parse_expression() if alias else self._parse_assignment()
6668        )
6669
6670    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
6671        return self._parse_query_modifiers(
6672            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
6673        )
6674
6675    def _parse_transaction(self) -> exp.Transaction | exp.Command:
6676        this = None
6677        if self._match_texts(self.TRANSACTION_KIND):
6678            this = self._prev.text
6679
6680        self._match_texts(("TRANSACTION", "WORK"))
6681
6682        modes = []
6683        while True:
6684            mode = []
6685            while self._match(TokenType.VAR):
6686                mode.append(self._prev.text)
6687
6688            if mode:
6689                modes.append(" ".join(mode))
6690            if not self._match(TokenType.COMMA):
6691                break
6692
6693        return self.expression(exp.Transaction, this=this, modes=modes)
6694
6695    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
6696        chain = None
6697        savepoint = None
6698        is_rollback = self._prev.token_type == TokenType.ROLLBACK
6699
6700        self._match_texts(("TRANSACTION", "WORK"))
6701
6702        if self._match_text_seq("TO"):
6703            self._match_text_seq("SAVEPOINT")
6704            savepoint = self._parse_id_var()
6705
6706        if self._match(TokenType.AND):
6707            chain = not self._match_text_seq("NO")
6708            self._match_text_seq("CHAIN")
6709
6710        if is_rollback:
6711            return self.expression(exp.Rollback, savepoint=savepoint)
6712
6713        return self.expression(exp.Commit, chain=chain)
6714
6715    def _parse_refresh(self) -> exp.Refresh:
6716        self._match(TokenType.TABLE)
6717        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
6718
6719    def _parse_add_column(self) -> t.Optional[exp.Expression]:
6720        if not self._match_text_seq("ADD"):
6721            return None
6722
6723        self._match(TokenType.COLUMN)
6724        exists_column = self._parse_exists(not_=True)
6725        expression = self._parse_field_def()
6726
6727        if expression:
6728            expression.set("exists", exists_column)
6729
6730            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
6731            if self._match_texts(("FIRST", "AFTER")):
6732                position = self._prev.text
6733                column_position = self.expression(
6734                    exp.ColumnPosition, this=self._parse_column(), position=position
6735                )
6736                expression.set("position", column_position)
6737
6738        return expression
6739
6740    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
6741        drop = self._match(TokenType.DROP) and self._parse_drop()
6742        if drop and not isinstance(drop, exp.Command):
6743            drop.set("kind", drop.args.get("kind", "COLUMN"))
6744        return drop
6745
6746    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
6747    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
6748        return self.expression(
6749            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
6750        )
6751
6752    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
6753        index = self._index - 1
6754
6755        if self._match_set(self.ADD_CONSTRAINT_TOKENS, advance=False):
6756            return self._parse_csv(
6757                lambda: self.expression(
6758                    exp.AddConstraint, expressions=self._parse_csv(self._parse_constraint)
6759                )
6760            )
6761
6762        self._retreat(index)
6763        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
6764            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
6765
6766        if self._match_text_seq("ADD", "COLUMNS"):
6767            schema = self._parse_schema()
6768            if schema:
6769                return [schema]
6770            return []
6771
6772        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
6773
6774    def _parse_alter_table_alter(self) -> t.Optional[exp.Expression]:
6775        if self._match_texts(self.ALTER_ALTER_PARSERS):
6776            return self.ALTER_ALTER_PARSERS[self._prev.text.upper()](self)
6777
6778        # Many dialects support the ALTER [COLUMN] syntax, so if there is no
6779        # keyword after ALTER we default to parsing this statement
6780        self._match(TokenType.COLUMN)
6781        column = self._parse_field(any_token=True)
6782
6783        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
6784            return self.expression(exp.AlterColumn, this=column, drop=True)
6785        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
6786            return self.expression(exp.AlterColumn, this=column, default=self._parse_assignment())
6787        if self._match(TokenType.COMMENT):
6788            return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
6789        if self._match_text_seq("DROP", "NOT", "NULL"):
6790            return self.expression(
6791                exp.AlterColumn,
6792                this=column,
6793                drop=True,
6794                allow_null=True,
6795            )
6796        if self._match_text_seq("SET", "NOT", "NULL"):
6797            return self.expression(
6798                exp.AlterColumn,
6799                this=column,
6800                allow_null=False,
6801            )
6802        self._match_text_seq("SET", "DATA")
6803        self._match_text_seq("TYPE")
6804        return self.expression(
6805            exp.AlterColumn,
6806            this=column,
6807            dtype=self._parse_types(),
6808            collate=self._match(TokenType.COLLATE) and self._parse_term(),
6809            using=self._match(TokenType.USING) and self._parse_assignment(),
6810        )
6811
6812    def _parse_alter_diststyle(self) -> exp.AlterDistStyle:
6813        if self._match_texts(("ALL", "EVEN", "AUTO")):
6814            return self.expression(exp.AlterDistStyle, this=exp.var(self._prev.text.upper()))
6815
6816        self._match_text_seq("KEY", "DISTKEY")
6817        return self.expression(exp.AlterDistStyle, this=self._parse_column())
6818
6819    def _parse_alter_sortkey(self, compound: t.Optional[bool] = None) -> exp.AlterSortKey:
6820        if compound:
6821            self._match_text_seq("SORTKEY")
6822
6823        if self._match(TokenType.L_PAREN, advance=False):
6824            return self.expression(
6825                exp.AlterSortKey, expressions=self._parse_wrapped_id_vars(), compound=compound
6826            )
6827
6828        self._match_texts(("AUTO", "NONE"))
6829        return self.expression(
6830            exp.AlterSortKey, this=exp.var(self._prev.text.upper()), compound=compound
6831        )
6832
6833    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
6834        index = self._index - 1
6835
6836        partition_exists = self._parse_exists()
6837        if self._match(TokenType.PARTITION, advance=False):
6838            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
6839
6840        self._retreat(index)
6841        return self._parse_csv(self._parse_drop_column)
6842
6843    def _parse_alter_table_rename(self) -> t.Optional[exp.AlterRename | exp.RenameColumn]:
6844        if self._match(TokenType.COLUMN):
6845            exists = self._parse_exists()
6846            old_column = self._parse_column()
6847            to = self._match_text_seq("TO")
6848            new_column = self._parse_column()
6849
6850            if old_column is None or to is None or new_column is None:
6851                return None
6852
6853            return self.expression(exp.RenameColumn, this=old_column, to=new_column, exists=exists)
6854
6855        self._match_text_seq("TO")
6856        return self.expression(exp.AlterRename, this=self._parse_table(schema=True))
6857
6858    def _parse_alter_table_set(self) -> exp.AlterSet:
6859        alter_set = self.expression(exp.AlterSet)
6860
6861        if self._match(TokenType.L_PAREN, advance=False) or self._match_text_seq(
6862            "TABLE", "PROPERTIES"
6863        ):
6864            alter_set.set("expressions", self._parse_wrapped_csv(self._parse_assignment))
6865        elif self._match_text_seq("FILESTREAM_ON", advance=False):
6866            alter_set.set("expressions", [self._parse_assignment()])
6867        elif self._match_texts(("LOGGED", "UNLOGGED")):
6868            alter_set.set("option", exp.var(self._prev.text.upper()))
6869        elif self._match_text_seq("WITHOUT") and self._match_texts(("CLUSTER", "OIDS")):
6870            alter_set.set("option", exp.var(f"WITHOUT {self._prev.text.upper()}"))
6871        elif self._match_text_seq("LOCATION"):
6872            alter_set.set("location", self._parse_field())
6873        elif self._match_text_seq("ACCESS", "METHOD"):
6874            alter_set.set("access_method", self._parse_field())
6875        elif self._match_text_seq("TABLESPACE"):
6876            alter_set.set("tablespace", self._parse_field())
6877        elif self._match_text_seq("FILE", "FORMAT") or self._match_text_seq("FILEFORMAT"):
6878            alter_set.set("file_format", [self._parse_field()])
6879        elif self._match_text_seq("STAGE_FILE_FORMAT"):
6880            alter_set.set("file_format", self._parse_wrapped_options())
6881        elif self._match_text_seq("STAGE_COPY_OPTIONS"):
6882            alter_set.set("copy_options", self._parse_wrapped_options())
6883        elif self._match_text_seq("TAG") or self._match_text_seq("TAGS"):
6884            alter_set.set("tag", self._parse_csv(self._parse_assignment))
6885        else:
6886            if self._match_text_seq("SERDE"):
6887                alter_set.set("serde", self._parse_field())
6888
6889            alter_set.set("expressions", [self._parse_properties()])
6890
6891        return alter_set
6892
6893    def _parse_alter(self) -> exp.Alter | exp.Command:
6894        start = self._prev
6895
6896        alter_token = self._match_set(self.ALTERABLES) and self._prev
6897        if not alter_token:
6898            return self._parse_as_command(start)
6899
6900        exists = self._parse_exists()
6901        only = self._match_text_seq("ONLY")
6902        this = self._parse_table(schema=True)
6903        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
6904
6905        if self._next:
6906            self._advance()
6907
6908        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
6909        if parser:
6910            actions = ensure_list(parser(self))
6911            not_valid = self._match_text_seq("NOT", "VALID")
6912            options = self._parse_csv(self._parse_property)
6913
6914            if not self._curr and actions:
6915                return self.expression(
6916                    exp.Alter,
6917                    this=this,
6918                    kind=alter_token.text.upper(),
6919                    exists=exists,
6920                    actions=actions,
6921                    only=only,
6922                    options=options,
6923                    cluster=cluster,
6924                    not_valid=not_valid,
6925                )
6926
6927        return self._parse_as_command(start)
6928
6929    def _parse_merge(self) -> exp.Merge:
6930        self._match(TokenType.INTO)
6931        target = self._parse_table()
6932
6933        if target and self._match(TokenType.ALIAS, advance=False):
6934            target.set("alias", self._parse_table_alias())
6935
6936        self._match(TokenType.USING)
6937        using = self._parse_table()
6938
6939        self._match(TokenType.ON)
6940        on = self._parse_assignment()
6941
6942        return self.expression(
6943            exp.Merge,
6944            this=target,
6945            using=using,
6946            on=on,
6947            expressions=self._parse_when_matched(),
6948            returning=self._parse_returning(),
6949        )
6950
6951    def _parse_when_matched(self) -> t.List[exp.When]:
6952        whens = []
6953
6954        while self._match(TokenType.WHEN):
6955            matched = not self._match(TokenType.NOT)
6956            self._match_text_seq("MATCHED")
6957            source = (
6958                False
6959                if self._match_text_seq("BY", "TARGET")
6960                else self._match_text_seq("BY", "SOURCE")
6961            )
6962            condition = self._parse_assignment() if self._match(TokenType.AND) else None
6963
6964            self._match(TokenType.THEN)
6965
6966            if self._match(TokenType.INSERT):
6967                this = self._parse_star()
6968                if this:
6969                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=this)
6970                else:
6971                    then = self.expression(
6972                        exp.Insert,
6973                        this=exp.var("ROW") if self._match_text_seq("ROW") else self._parse_value(),
6974                        expression=self._match_text_seq("VALUES") and self._parse_value(),
6975                    )
6976            elif self._match(TokenType.UPDATE):
6977                expressions = self._parse_star()
6978                if expressions:
6979                    then = self.expression(exp.Update, expressions=expressions)
6980                else:
6981                    then = self.expression(
6982                        exp.Update,
6983                        expressions=self._match(TokenType.SET)
6984                        and self._parse_csv(self._parse_equality),
6985                    )
6986            elif self._match(TokenType.DELETE):
6987                then = self.expression(exp.Var, this=self._prev.text)
6988            else:
6989                then = self._parse_var_from_options(self.CONFLICT_ACTIONS)
6990
6991            whens.append(
6992                self.expression(
6993                    exp.When,
6994                    matched=matched,
6995                    source=source,
6996                    condition=condition,
6997                    then=then,
6998                )
6999            )
7000        return whens
7001
7002    def _parse_show(self) -> t.Optional[exp.Expression]:
7003        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
7004        if parser:
7005            return parser(self)
7006        return self._parse_as_command(self._prev)
7007
7008    def _parse_set_item_assignment(
7009        self, kind: t.Optional[str] = None
7010    ) -> t.Optional[exp.Expression]:
7011        index = self._index
7012
7013        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
7014            return self._parse_set_transaction(global_=kind == "GLOBAL")
7015
7016        left = self._parse_primary() or self._parse_column()
7017        assignment_delimiter = self._match_texts(("=", "TO"))
7018
7019        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
7020            self._retreat(index)
7021            return None
7022
7023        right = self._parse_statement() or self._parse_id_var()
7024        if isinstance(right, (exp.Column, exp.Identifier)):
7025            right = exp.var(right.name)
7026
7027        this = self.expression(exp.EQ, this=left, expression=right)
7028        return self.expression(exp.SetItem, this=this, kind=kind)
7029
7030    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
7031        self._match_text_seq("TRANSACTION")
7032        characteristics = self._parse_csv(
7033            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
7034        )
7035        return self.expression(
7036            exp.SetItem,
7037            expressions=characteristics,
7038            kind="TRANSACTION",
7039            **{"global": global_},  # type: ignore
7040        )
7041
7042    def _parse_set_item(self) -> t.Optional[exp.Expression]:
7043        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
7044        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
7045
7046    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
7047        index = self._index
7048        set_ = self.expression(
7049            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
7050        )
7051
7052        if self._curr:
7053            self._retreat(index)
7054            return self._parse_as_command(self._prev)
7055
7056        return set_
7057
7058    def _parse_var_from_options(
7059        self, options: OPTIONS_TYPE, raise_unmatched: bool = True
7060    ) -> t.Optional[exp.Var]:
7061        start = self._curr
7062        if not start:
7063            return None
7064
7065        option = start.text.upper()
7066        continuations = options.get(option)
7067
7068        index = self._index
7069        self._advance()
7070        for keywords in continuations or []:
7071            if isinstance(keywords, str):
7072                keywords = (keywords,)
7073
7074            if self._match_text_seq(*keywords):
7075                option = f"{option} {' '.join(keywords)}"
7076                break
7077        else:
7078            if continuations or continuations is None:
7079                if raise_unmatched:
7080                    self.raise_error(f"Unknown option {option}")
7081
7082                self._retreat(index)
7083                return None
7084
7085        return exp.var(option)
7086
7087    def _parse_as_command(self, start: Token) -> exp.Command:
7088        while self._curr:
7089            self._advance()
7090        text = self._find_sql(start, self._prev)
7091        size = len(start.text)
7092        self._warn_unsupported()
7093        return exp.Command(this=text[:size], expression=text[size:])
7094
7095    def _parse_dict_property(self, this: str) -> exp.DictProperty:
7096        settings = []
7097
7098        self._match_l_paren()
7099        kind = self._parse_id_var()
7100
7101        if self._match(TokenType.L_PAREN):
7102            while True:
7103                key = self._parse_id_var()
7104                value = self._parse_primary()
7105
7106                if not key and value is None:
7107                    break
7108                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
7109            self._match(TokenType.R_PAREN)
7110
7111        self._match_r_paren()
7112
7113        return self.expression(
7114            exp.DictProperty,
7115            this=this,
7116            kind=kind.this if kind else None,
7117            settings=settings,
7118        )
7119
7120    def _parse_dict_range(self, this: str) -> exp.DictRange:
7121        self._match_l_paren()
7122        has_min = self._match_text_seq("MIN")
7123        if has_min:
7124            min = self._parse_var() or self._parse_primary()
7125            self._match_text_seq("MAX")
7126            max = self._parse_var() or self._parse_primary()
7127        else:
7128            max = self._parse_var() or self._parse_primary()
7129            min = exp.Literal.number(0)
7130        self._match_r_paren()
7131        return self.expression(exp.DictRange, this=this, min=min, max=max)
7132
7133    def _parse_comprehension(
7134        self, this: t.Optional[exp.Expression]
7135    ) -> t.Optional[exp.Comprehension]:
7136        index = self._index
7137        expression = self._parse_column()
7138        if not self._match(TokenType.IN):
7139            self._retreat(index - 1)
7140            return None
7141        iterator = self._parse_column()
7142        condition = self._parse_assignment() if self._match_text_seq("IF") else None
7143        return self.expression(
7144            exp.Comprehension,
7145            this=this,
7146            expression=expression,
7147            iterator=iterator,
7148            condition=condition,
7149        )
7150
7151    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
7152        if self._match(TokenType.HEREDOC_STRING):
7153            return self.expression(exp.Heredoc, this=self._prev.text)
7154
7155        if not self._match_text_seq("$"):
7156            return None
7157
7158        tags = ["$"]
7159        tag_text = None
7160
7161        if self._is_connected():
7162            self._advance()
7163            tags.append(self._prev.text.upper())
7164        else:
7165            self.raise_error("No closing $ found")
7166
7167        if tags[-1] != "$":
7168            if self._is_connected() and self._match_text_seq("$"):
7169                tag_text = tags[-1]
7170                tags.append("$")
7171            else:
7172                self.raise_error("No closing $ found")
7173
7174        heredoc_start = self._curr
7175
7176        while self._curr:
7177            if self._match_text_seq(*tags, advance=False):
7178                this = self._find_sql(heredoc_start, self._prev)
7179                self._advance(len(tags))
7180                return self.expression(exp.Heredoc, this=this, tag=tag_text)
7181
7182            self._advance()
7183
7184        self.raise_error(f"No closing {''.join(tags)} found")
7185        return None
7186
7187    def _find_parser(
7188        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
7189    ) -> t.Optional[t.Callable]:
7190        if not self._curr:
7191            return None
7192
7193        index = self._index
7194        this = []
7195        while True:
7196            # The current token might be multiple words
7197            curr = self._curr.text.upper()
7198            key = curr.split(" ")
7199            this.append(curr)
7200
7201            self._advance()
7202            result, trie = in_trie(trie, key)
7203            if result == TrieResult.FAILED:
7204                break
7205
7206            if result == TrieResult.EXISTS:
7207                subparser = parsers[" ".join(this)]
7208                return subparser
7209
7210        self._retreat(index)
7211        return None
7212
7213    def _match(self, token_type, advance=True, expression=None):
7214        if not self._curr:
7215            return None
7216
7217        if self._curr.token_type == token_type:
7218            if advance:
7219                self._advance()
7220            self._add_comments(expression)
7221            return True
7222
7223        return None
7224
7225    def _match_set(self, types, advance=True):
7226        if not self._curr:
7227            return None
7228
7229        if self._curr.token_type in types:
7230            if advance:
7231                self._advance()
7232            return True
7233
7234        return None
7235
7236    def _match_pair(self, token_type_a, token_type_b, advance=True):
7237        if not self._curr or not self._next:
7238            return None
7239
7240        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
7241            if advance:
7242                self._advance(2)
7243            return True
7244
7245        return None
7246
7247    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
7248        if not self._match(TokenType.L_PAREN, expression=expression):
7249            self.raise_error("Expecting (")
7250
7251    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
7252        if not self._match(TokenType.R_PAREN, expression=expression):
7253            self.raise_error("Expecting )")
7254
7255    def _match_texts(self, texts, advance=True):
7256        if (
7257            self._curr
7258            and self._curr.token_type != TokenType.STRING
7259            and self._curr.text.upper() in texts
7260        ):
7261            if advance:
7262                self._advance()
7263            return True
7264        return None
7265
7266    def _match_text_seq(self, *texts, advance=True):
7267        index = self._index
7268        for text in texts:
7269            if (
7270                self._curr
7271                and self._curr.token_type != TokenType.STRING
7272                and self._curr.text.upper() == text
7273            ):
7274                self._advance()
7275            else:
7276                self._retreat(index)
7277                return None
7278
7279        if not advance:
7280            self._retreat(index)
7281
7282        return True
7283
7284    def _replace_lambda(
7285        self, node: t.Optional[exp.Expression], expressions: t.List[exp.Expression]
7286    ) -> t.Optional[exp.Expression]:
7287        if not node:
7288            return node
7289
7290        lambda_types = {e.name: e.args.get("to") or False for e in expressions}
7291
7292        for column in node.find_all(exp.Column):
7293            typ = lambda_types.get(column.parts[0].name)
7294            if typ is not None:
7295                dot_or_id = column.to_dot() if column.table else column.this
7296
7297                if typ:
7298                    dot_or_id = self.expression(
7299                        exp.Cast,
7300                        this=dot_or_id,
7301                        to=typ,
7302                    )
7303
7304                parent = column.parent
7305
7306                while isinstance(parent, exp.Dot):
7307                    if not isinstance(parent.parent, exp.Dot):
7308                        parent.replace(dot_or_id)
7309                        break
7310                    parent = parent.parent
7311                else:
7312                    if column is node:
7313                        node = dot_or_id
7314                    else:
7315                        column.replace(dot_or_id)
7316        return node
7317
7318    def _parse_truncate_table(self) -> t.Optional[exp.TruncateTable] | exp.Expression:
7319        start = self._prev
7320
7321        # Not to be confused with TRUNCATE(number, decimals) function call
7322        if self._match(TokenType.L_PAREN):
7323            self._retreat(self._index - 2)
7324            return self._parse_function()
7325
7326        # Clickhouse supports TRUNCATE DATABASE as well
7327        is_database = self._match(TokenType.DATABASE)
7328
7329        self._match(TokenType.TABLE)
7330
7331        exists = self._parse_exists(not_=False)
7332
7333        expressions = self._parse_csv(
7334            lambda: self._parse_table(schema=True, is_db_reference=is_database)
7335        )
7336
7337        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
7338
7339        if self._match_text_seq("RESTART", "IDENTITY"):
7340            identity = "RESTART"
7341        elif self._match_text_seq("CONTINUE", "IDENTITY"):
7342            identity = "CONTINUE"
7343        else:
7344            identity = None
7345
7346        if self._match_text_seq("CASCADE") or self._match_text_seq("RESTRICT"):
7347            option = self._prev.text
7348        else:
7349            option = None
7350
7351        partition = self._parse_partition()
7352
7353        # Fallback case
7354        if self._curr:
7355            return self._parse_as_command(start)
7356
7357        return self.expression(
7358            exp.TruncateTable,
7359            expressions=expressions,
7360            is_database=is_database,
7361            exists=exists,
7362            cluster=cluster,
7363            identity=identity,
7364            option=option,
7365            partition=partition,
7366        )
7367
7368    def _parse_with_operator(self) -> t.Optional[exp.Expression]:
7369        this = self._parse_ordered(self._parse_opclass)
7370
7371        if not self._match(TokenType.WITH):
7372            return this
7373
7374        op = self._parse_var(any_token=True)
7375
7376        return self.expression(exp.WithOperator, this=this, op=op)
7377
7378    def _parse_wrapped_options(self) -> t.List[t.Optional[exp.Expression]]:
7379        self._match(TokenType.EQ)
7380        self._match(TokenType.L_PAREN)
7381
7382        opts: t.List[t.Optional[exp.Expression]] = []
7383        while self._curr and not self._match(TokenType.R_PAREN):
7384            if self._match_text_seq("FORMAT_NAME", "="):
7385                # The FORMAT_NAME can be set to an identifier for Snowflake and T-SQL,
7386                # so we parse it separately to use _parse_field()
7387                prop = self.expression(
7388                    exp.Property, this=exp.var("FORMAT_NAME"), value=self._parse_field()
7389                )
7390                opts.append(prop)
7391            else:
7392                opts.append(self._parse_property())
7393
7394            self._match(TokenType.COMMA)
7395
7396        return opts
7397
7398    def _parse_copy_parameters(self) -> t.List[exp.CopyParameter]:
7399        sep = TokenType.COMMA if self.dialect.COPY_PARAMS_ARE_CSV else None
7400
7401        options = []
7402        while self._curr and not self._match(TokenType.R_PAREN, advance=False):
7403            option = self._parse_var(any_token=True)
7404            prev = self._prev.text.upper()
7405
7406            # Different dialects might separate options and values by white space, "=" and "AS"
7407            self._match(TokenType.EQ)
7408            self._match(TokenType.ALIAS)
7409
7410            param = self.expression(exp.CopyParameter, this=option)
7411
7412            if prev in self.COPY_INTO_VARLEN_OPTIONS and self._match(
7413                TokenType.L_PAREN, advance=False
7414            ):
7415                # Snowflake FILE_FORMAT case, Databricks COPY & FORMAT options
7416                param.set("expressions", self._parse_wrapped_options())
7417            elif prev == "FILE_FORMAT":
7418                # T-SQL's external file format case
7419                param.set("expression", self._parse_field())
7420            else:
7421                param.set("expression", self._parse_unquoted_field())
7422
7423            options.append(param)
7424            self._match(sep)
7425
7426        return options
7427
7428    def _parse_credentials(self) -> t.Optional[exp.Credentials]:
7429        expr = self.expression(exp.Credentials)
7430
7431        if self._match_text_seq("STORAGE_INTEGRATION", "="):
7432            expr.set("storage", self._parse_field())
7433        if self._match_text_seq("CREDENTIALS"):
7434            # Snowflake case: CREDENTIALS = (...), Redshift case: CREDENTIALS <string>
7435            creds = (
7436                self._parse_wrapped_options() if self._match(TokenType.EQ) else self._parse_field()
7437            )
7438            expr.set("credentials", creds)
7439        if self._match_text_seq("ENCRYPTION"):
7440            expr.set("encryption", self._parse_wrapped_options())
7441        if self._match_text_seq("IAM_ROLE"):
7442            expr.set("iam_role", self._parse_field())
7443        if self._match_text_seq("REGION"):
7444            expr.set("region", self._parse_field())
7445
7446        return expr
7447
7448    def _parse_file_location(self) -> t.Optional[exp.Expression]:
7449        return self._parse_field()
7450
7451    def _parse_copy(self) -> exp.Copy | exp.Command:
7452        start = self._prev
7453
7454        self._match(TokenType.INTO)
7455
7456        this = (
7457            self._parse_select(nested=True, parse_subquery_alias=False)
7458            if self._match(TokenType.L_PAREN, advance=False)
7459            else self._parse_table(schema=True)
7460        )
7461
7462        kind = self._match(TokenType.FROM) or not self._match_text_seq("TO")
7463
7464        files = self._parse_csv(self._parse_file_location)
7465        credentials = self._parse_credentials()
7466
7467        self._match_text_seq("WITH")
7468
7469        params = self._parse_wrapped(self._parse_copy_parameters, optional=True)
7470
7471        # Fallback case
7472        if self._curr:
7473            return self._parse_as_command(start)
7474
7475        return self.expression(
7476            exp.Copy,
7477            this=this,
7478            kind=kind,
7479            credentials=credentials,
7480            files=files,
7481            params=params,
7482        )
7483
7484    def _parse_normalize(self) -> exp.Normalize:
7485        return self.expression(
7486            exp.Normalize,
7487            this=self._parse_bitwise(),
7488            form=self._match(TokenType.COMMA) and self._parse_var(),
7489        )
7490
7491    def _parse_star_ops(self) -> t.Optional[exp.Expression]:
7492        if self._match_text_seq("COLUMNS", "(", advance=False):
7493            this = self._parse_function()
7494            if isinstance(this, exp.Columns):
7495                this.set("unpack", True)
7496            return this
7497
7498        return self.expression(
7499            exp.Star,
7500            **{  # type: ignore
7501                "except": self._parse_star_op("EXCEPT", "EXCLUDE"),
7502                "replace": self._parse_star_op("REPLACE"),
7503                "rename": self._parse_star_op("RENAME"),
7504            },
7505        )
7506
7507    def _parse_grant_privilege(self) -> t.Optional[exp.GrantPrivilege]:
7508        privilege_parts = []
7509
7510        # Keep consuming consecutive keywords until comma (end of this privilege) or ON
7511        # (end of privilege list) or L_PAREN (start of column list) are met
7512        while self._curr and not self._match_set(self.PRIVILEGE_FOLLOW_TOKENS, advance=False):
7513            privilege_parts.append(self._curr.text.upper())
7514            self._advance()
7515
7516        this = exp.var(" ".join(privilege_parts))
7517        expressions = (
7518            self._parse_wrapped_csv(self._parse_column)
7519            if self._match(TokenType.L_PAREN, advance=False)
7520            else None
7521        )
7522
7523        return self.expression(exp.GrantPrivilege, this=this, expressions=expressions)
7524
7525    def _parse_grant_principal(self) -> t.Optional[exp.GrantPrincipal]:
7526        kind = self._match_texts(("ROLE", "GROUP")) and self._prev.text.upper()
7527        principal = self._parse_id_var()
7528
7529        if not principal:
7530            return None
7531
7532        return self.expression(exp.GrantPrincipal, this=principal, kind=kind)
7533
7534    def _parse_grant(self) -> exp.Grant | exp.Command:
7535        start = self._prev
7536
7537        privileges = self._parse_csv(self._parse_grant_privilege)
7538
7539        self._match(TokenType.ON)
7540        kind = self._match_set(self.CREATABLES) and self._prev.text.upper()
7541
7542        # Attempt to parse the securable e.g. MySQL allows names
7543        # such as "foo.*", "*.*" which are not easily parseable yet
7544        securable = self._try_parse(self._parse_table_parts)
7545
7546        if not securable or not self._match_text_seq("TO"):
7547            return self._parse_as_command(start)
7548
7549        principals = self._parse_csv(self._parse_grant_principal)
7550
7551        grant_option = self._match_text_seq("WITH", "GRANT", "OPTION")
7552
7553        if self._curr:
7554            return self._parse_as_command(start)
7555
7556        return self.expression(
7557            exp.Grant,
7558            privileges=privileges,
7559            kind=kind,
7560            securable=securable,
7561            principals=principals,
7562            grant_option=grant_option,
7563        )
7564
7565    def _parse_overlay(self) -> exp.Overlay:
7566        return self.expression(
7567            exp.Overlay,
7568            **{  # type: ignore
7569                "this": self._parse_bitwise(),
7570                "expression": self._match_text_seq("PLACING") and self._parse_bitwise(),
7571                "from": self._match_text_seq("FROM") and self._parse_bitwise(),
7572                "for": self._match_text_seq("FOR") and self._parse_bitwise(),
7573            },
7574        )

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.Dialect, Type[sqlglot.dialects.dialect.Dialect], NoneType] = None)
1379    def __init__(
1380        self,
1381        error_level: t.Optional[ErrorLevel] = None,
1382        error_message_context: int = 100,
1383        max_errors: int = 3,
1384        dialect: DialectType = None,
1385    ):
1386        from sqlglot.dialects import Dialect
1387
1388        self.error_level = error_level or ErrorLevel.IMMEDIATE
1389        self.error_message_context = error_message_context
1390        self.max_errors = max_errors
1391        self.dialect = Dialect.get_or_raise(dialect)
1392        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'>>, 'ANONYMOUS_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AnonymousAggFunc'>>, 'ANY_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.AnyValue'>>, 'APPLY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Apply'>>, 'APPROX_DISTINCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxDistinct'>>, 'APPROX_COUNT_DISTINCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxDistinct'>>, 'APPROX_QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxQuantile'>>, 'APPROX_TOP_K': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ApproxTopK'>>, 'ARG_MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'ARGMAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'MAX_BY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMax'>>, 'ARG_MIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'ARGMIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'MIN_BY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArgMin'>>, 'ARRAY': <function Parser.<lambda>>, 'ARRAY_AGG': <function Parser.<lambda>>, 'ARRAY_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAll'>>, 'ARRAY_ANY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAny'>>, 'ARRAY_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConcat'>>, 'ARRAY_CAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConcat'>>, 'ARRAY_CONSTRUCT_COMPACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayConstructCompact'>>, 'ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContains'>>, 'ARRAY_HAS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContains'>>, 'ARRAY_CONTAINS_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContainsAll'>>, 'ARRAY_HAS_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContainsAll'>>, 'FILTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayFilter'>>, 'ARRAY_FILTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayFilter'>>, 'ARRAY_OVERLAPS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayOverlaps'>>, 'ARRAY_SIZE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySize'>>, 'ARRAY_LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySize'>>, 'ARRAY_SORT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySort'>>, 'ARRAY_SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArraySum'>>, 'ARRAY_TO_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayToString'>>, 'ARRAY_JOIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayToString'>>, 'ARRAY_UNION_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUnionAgg'>>, 'ARRAY_UNIQUE_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayUniqueAgg'>>, 'AVG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Avg'>>, 'CASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Case'>>, 'CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Cast'>>, 'CAST_TO_STR_TYPE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CastToStrType'>>, 'CBRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Cbrt'>>, 'CEIL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CEILING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ceil'>>, 'CHR': <function Parser.<lambda>>, 'CHAR': <function Parser.<lambda>>, 'COALESCE': <function build_coalesce>, 'IFNULL': <function build_coalesce>, 'NVL': <function build_coalesce>, 'COLLATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Collate'>>, 'COLUMNS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Columns'>>, 'COMBINED_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedAggFunc'>>, 'COMBINED_PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedParameterizedAgg'>>, 'CONCAT': <function Parser.<lambda>>, 'CONCAT_WS': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ConnectByRoot'>>, 'CONVERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Convert'>>, 'CONVERT_TIMEZONE': <function build_convert_timezone>, 'CORR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Corr'>>, 'COUNT': <function Parser.<lambda>>, 'COUNT_IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, 'COUNTIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, 'COVAR_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CovarPop'>>, 'COVAR_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CovarSamp'>>, 'CURRENT_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDate'>>, 'CURRENT_DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDatetime'>>, 'CURRENT_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTime'>>, 'CURRENT_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentTimestamp'>>, 'CURRENT_USER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentUser'>>, 'DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Date'>>, 'DATE_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateAdd'>>, 'DATEDIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateDiff'>>, 'DATE_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateDiff'>>, 'DATE_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromParts'>>, 'DATEFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateFromParts'>>, 'DATE_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateStrToDate'>>, 'DATE_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateSub'>>, 'DATE_TO_DATE_STR': <function Parser.<lambda>>, 'DATE_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateToDi'>>, 'DATE_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DateTrunc'>>, 'DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Datetime'>>, 'DATETIME_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeAdd'>>, 'DATETIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeDiff'>>, 'DATETIME_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeSub'>>, 'DATETIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DatetimeTrunc'>>, 'DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Day'>>, 'DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfMonth'>>, 'DAYOFMONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfMonth'>>, 'DAY_OF_WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeek'>>, 'DAYOFWEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeek'>>, 'DAYOFWEEK_ISO': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeekIso'>>, 'ISODOW': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfWeekIso'>>, 'DAY_OF_YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfYear'>>, 'DAYOFYEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DayOfYear'>>, 'DECODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Decode'>>, 'DI_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.DiToDate'>>, 'ENCODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Encode'>>, 'EXISTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Exists'>>, 'EXP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Exp'>>, 'EXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Explode'>>, 'EXPLODE_OUTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ExplodeOuter'>>, 'EXPLODING_GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ExplodingGenerateSeries'>>, 'EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Extract'>>, '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'>>, '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_EXISTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExists'>>, 'JSON_EXTRACT': <function build_extract_json_with_path.<locals>._builder>, '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'>>, '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'>>, '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'>>, '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'>>, '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_I_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpILike'>>, 'REGEXP_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpLike'>>, 'REGEXP_REPLACE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpReplace'>>, 'REGEXP_SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpSplit'>>, 'REPEAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Repeat'>>, 'RIGHT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Right'>>, 'ROUND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Round'>>, 'ROW_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RowNumber'>>, 'SHA': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA1': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA2'>>, 'SAFE_DIVIDE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeDivide'>>, 'SIGN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SIGNUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SORT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SortArray'>>, 'SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Split'>>, 'SPLIT_PART': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SplitPart'>>, 'SQRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sqrt'>>, 'STANDARD_HASH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StandardHash'>>, 'STAR_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StarMap'>>, 'STARTS_WITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STARTSWITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STDDEV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stddev'>>, 'STDEV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stddev'>>, 'STDDEV_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevPop'>>, 'STDDEV_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevSamp'>>, 'STR_POSITION': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToDate'>>, 'STR_TO_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToMap'>>, 'STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToTime'>>, 'STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToUnix'>>, 'STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.String'>>, 'STRING_TO_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StringToArray'>>, 'SPLIT_BY_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StringToArray'>>, 'STRUCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Struct'>>, 'STRUCT_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StructExtract'>>, 'STUFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'INSERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'SUBSTRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Substring'>>, 'SUBSTR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Substring'>>, 'SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sum'>>, 'TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Time'>>, 'TIME_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeAdd'>>, 'TIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeDiff'>>, 'TIME_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeFromParts'>>, 'TIMEFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeFromParts'>>, 'TIME_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToDate'>>, 'TIME_STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToTime'>>, 'TIME_STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToUnix'>>, 'TIME_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeSub'>>, 'TIME_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToStr'>>, 'TIME_TO_TIME_STR': <function Parser.<lambda>>, 'TIME_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToUnix'>>, 'TIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeTrunc'>>, 'TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Timestamp'>>, 'TIMESTAMP_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampAdd'>>, 'TIMESTAMPDIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, 'TIMESTAMPFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, 'TIMESTAMP_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampSub'>>, 'TIMESTAMP_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampTrunc'>>, 'TO_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToArray'>>, 'TO_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToBase64'>>, 'TO_CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToChar'>>, 'TO_DAYS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToDays'>>, 'TO_DOUBLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToDouble'>>, 'TO_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToMap'>>, 'TO_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToNumber'>>, 'TRANSFORM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Transform'>>, 'TRIM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Trim'>>, 'TRY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Try'>>, 'TRY_CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TryCast'>>, 'TS_OR_DI_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDiToDi'>>, 'TS_OR_DS_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsAdd'>>, 'TS_OR_DS_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsDiff'>>, 'TS_OR_DS_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToDate'>>, 'TS_OR_DS_TO_DATE_STR': <function Parser.<lambda>>, 'TS_OR_DS_TO_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'>>, 'UNIX_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixDate'>>, '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'>>, 'WHEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.When'>>, '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>>, 'INSTR': <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>>, '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.OBJECT: 'OBJECT'>, <TokenType.UNION: 'UNION'>, <TokenType.STRUCT: 'STRUCT'>}
NESTED_TYPE_TOKENS = {<TokenType.NESTED: 'NESTED'>, <TokenType.MAP: 'MAP'>, <TokenType.LIST: 'LIST'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.RANGE: 'RANGE'>, <TokenType.UNION: 'UNION'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ARRAY: 'ARRAY'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.ENUM: 'ENUM'>}
AGGREGATE_TYPE_TOKENS = {<TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>}
TYPE_TOKENS = {<TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT: 'INT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.ENUM: 'ENUM'>, <TokenType.NULL: 'NULL'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.IPV6: 'IPV6'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.XML: 'XML'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.RANGE: 'RANGE'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BINARY: 'BINARY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.RING: 'RING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.UINT: 'UINT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.YEAR: 'YEAR'>, <TokenType.INET: 'INET'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MAP: 'MAP'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.UINT256: 'UINT256'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.UNION: 'UNION'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.UUID: 'UUID'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.DATE32: 'DATE32'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NAME: 'NAME'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CHAR: 'CHAR'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LIST: 'LIST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.IPV4: 'IPV4'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.TIME: 'TIME'>, <TokenType.TEXT: 'TEXT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TINYTEXT: 'TINYTEXT'>}
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'>}
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.R_BRACE: 'R_BRACE'>, <TokenType.COMMA: 'COMMA'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.PLUS: 'PLUS'>, <TokenType.SELECT: 'SELECT'>, <TokenType.HASH: 'HASH'>, <TokenType.COLON: 'COLON'>, <TokenType.LT: 'LT'>, <TokenType.MOD: 'MOD'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.EQ: 'EQ'>, <TokenType.GT: 'GT'>, <TokenType.DOT: 'DOT'>, <TokenType.TILDA: 'TILDA'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.CARET: 'CARET'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DASH: 'DASH'>, <TokenType.NOT: 'NOT'>, <TokenType.STAR: 'STAR'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.AMP: 'AMP'>, <TokenType.SLASH: 'SLASH'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.PIPE: 'PIPE'>}
DB_CREATABLES = {<TokenType.MODEL: 'MODEL'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TAG: 'TAG'>, <TokenType.VIEW: 'VIEW'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SEQUENCE: 'SEQUENCE'>}
CREATABLES = {<TokenType.MODEL: 'MODEL'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TAG: 'TAG'>, <TokenType.VIEW: 'VIEW'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.SEQUENCE: 'SEQUENCE'>}
ALTERABLES = {<TokenType.INDEX: 'INDEX'>, <TokenType.TABLE: 'TABLE'>, <TokenType.VIEW: 'VIEW'>}
ID_VAR_TOKENS = {<TokenType.PERCENT: 'PERCENT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.IS: 'IS'>, <TokenType.VIEW: 'VIEW'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT: 'INT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.FALSE: 'FALSE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.NULL: 'NULL'>, <TokenType.TAG: 'TAG'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ALL: 'ALL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.XML: 'XML'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BINARY: 'BINARY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SEMI: 'SEMI'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.ASC: 'ASC'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.RING: 'RING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.UINT: 'UINT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SET: 'SET'>, <TokenType.RENAME: 'RENAME'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.YEAR: 'YEAR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.LOAD: 'LOAD'>, <TokenType.INET: 'INET'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.POINT: 'POINT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.ROWS: 'ROWS'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DIV: 'DIV'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MAP: 'MAP'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT128: 'INT128'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.CUBE: 'CUBE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VAR: 'VAR'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.FULL: 'FULL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.COPY: 'COPY'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ROW: 'ROW'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UUID: 'UUID'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DATE32: 'DATE32'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NAME: 'NAME'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CHAR: 'CHAR'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LIST: 'LIST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.KILL: 'KILL'>, <TokenType.ASOF: 'ASOF'>, <TokenType.USE: 'USE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.IPV4: 'IPV4'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.TIME: 'TIME'>, <TokenType.TRUE: 'TRUE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DESC: 'DESC'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SOME: 'SOME'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ANY: 'ANY'>}
INTERVAL_VARS = {<TokenType.PERCENT: 'PERCENT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.IS: 'IS'>, <TokenType.VIEW: 'VIEW'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT: 'INT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.FALSE: 'FALSE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.NULL: 'NULL'>, <TokenType.TAG: 'TAG'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ALL: 'ALL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.XML: 'XML'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BINARY: 'BINARY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SEMI: 'SEMI'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.ASC: 'ASC'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.RING: 'RING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.UINT: 'UINT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SET: 'SET'>, <TokenType.RENAME: 'RENAME'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.YEAR: 'YEAR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.LOAD: 'LOAD'>, <TokenType.INET: 'INET'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.POINT: 'POINT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.ROWS: 'ROWS'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DIV: 'DIV'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MAP: 'MAP'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT128: 'INT128'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.CUBE: 'CUBE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VAR: 'VAR'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.FULL: 'FULL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.COPY: 'COPY'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ROW: 'ROW'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UUID: 'UUID'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DATE32: 'DATE32'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NAME: 'NAME'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CHAR: 'CHAR'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LIST: 'LIST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.KILL: 'KILL'>, <TokenType.ASOF: 'ASOF'>, <TokenType.USE: 'USE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.IPV4: 'IPV4'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.TIME: 'TIME'>, <TokenType.TRUE: 'TRUE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DESC: 'DESC'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SOME: 'SOME'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ANY: 'ANY'>}
TABLE_ALIAS_TOKENS = {<TokenType.PERCENT: 'PERCENT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.IS: 'IS'>, <TokenType.VIEW: 'VIEW'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT: 'INT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.FALSE: 'FALSE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.NULL: 'NULL'>, <TokenType.TAG: 'TAG'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ALL: 'ALL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.XML: 'XML'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BINARY: 'BINARY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.ASC: 'ASC'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.RING: 'RING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.UINT: 'UINT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SET: 'SET'>, <TokenType.RENAME: 'RENAME'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.YEAR: 'YEAR'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.LOAD: 'LOAD'>, <TokenType.INET: 'INET'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.POINT: 'POINT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.ROWS: 'ROWS'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DIV: 'DIV'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MAP: 'MAP'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT128: 'INT128'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VAR: 'VAR'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.COPY: 'COPY'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ROW: 'ROW'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UUID: 'UUID'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DATE32: 'DATE32'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NAME: 'NAME'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CHAR: 'CHAR'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LIST: 'LIST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.KILL: 'KILL'>, <TokenType.USE: 'USE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.IPV4: 'IPV4'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.TIME: 'TIME'>, <TokenType.TRUE: 'TRUE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DESC: 'DESC'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SOME: 'SOME'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ANY: 'ANY'>}
ALIAS_TOKENS = {<TokenType.PERCENT: 'PERCENT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.IS: 'IS'>, <TokenType.VIEW: 'VIEW'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT: 'INT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.FALSE: 'FALSE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.NULL: 'NULL'>, <TokenType.TAG: 'TAG'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ALL: 'ALL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.XML: 'XML'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BINARY: 'BINARY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SEMI: 'SEMI'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.ASC: 'ASC'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.RING: 'RING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.UINT: 'UINT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SET: 'SET'>, <TokenType.RENAME: 'RENAME'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.YEAR: 'YEAR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.LOAD: 'LOAD'>, <TokenType.INET: 'INET'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.POINT: 'POINT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.ROWS: 'ROWS'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DIV: 'DIV'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MAP: 'MAP'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT128: 'INT128'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.CUBE: 'CUBE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VAR: 'VAR'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.FULL: 'FULL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.COPY: 'COPY'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ROW: 'ROW'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UUID: 'UUID'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DATE32: 'DATE32'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NAME: 'NAME'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CHAR: 'CHAR'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LIST: 'LIST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.KILL: 'KILL'>, <TokenType.ASOF: 'ASOF'>, <TokenType.USE: 'USE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.IPV4: 'IPV4'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.TIME: 'TIME'>, <TokenType.TRUE: 'TRUE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DESC: 'DESC'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SOME: 'SOME'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ANY: 'ANY'>}
ARRAY_CONSTRUCTORS = {'ARRAY': <class 'sqlglot.expressions.Array'>, 'LIST': <class 'sqlglot.expressions.List'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.PERCENT: 'PERCENT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.VIEW: 'VIEW'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT: 'INT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.FALSE: 'FALSE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.NULL: 'NULL'>, <TokenType.TAG: 'TAG'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ALL: 'ALL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.XML: 'XML'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BINARY: 'BINARY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.ASC: 'ASC'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.RING: 'RING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.UINT: 'UINT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SET: 'SET'>, <TokenType.RENAME: 'RENAME'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.YEAR: 'YEAR'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.LOAD: 'LOAD'>, <TokenType.INET: 'INET'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.POINT: 'POINT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.ROWS: 'ROWS'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DIV: 'DIV'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MAP: 'MAP'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.INT128: 'INT128'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VAR: 'VAR'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.COPY: 'COPY'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ROW: 'ROW'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UUID: 'UUID'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DATE32: 'DATE32'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NAME: 'NAME'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CHAR: 'CHAR'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LIST: 'LIST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.KILL: 'KILL'>, <TokenType.USE: 'USE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.IPV4: 'IPV4'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.TIME: 'TIME'>, <TokenType.TRUE: 'TRUE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DESC: 'DESC'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SOME: 'SOME'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ANY: 'ANY'>}
UPDATE_ALIAS_TOKENS = {<TokenType.PERCENT: 'PERCENT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.IS: 'IS'>, <TokenType.VIEW: 'VIEW'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT: 'INT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.FALSE: 'FALSE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.NULL: 'NULL'>, <TokenType.TAG: 'TAG'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ALL: 'ALL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.XML: 'XML'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BINARY: 'BINARY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.ASC: 'ASC'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.RING: 'RING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.UINT: 'UINT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.RENAME: 'RENAME'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.YEAR: 'YEAR'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.LOAD: 'LOAD'>, <TokenType.INET: 'INET'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.FIRST: 'FIRST'>, <TokenType.POINT: 'POINT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.ROWS: 'ROWS'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DIV: 'DIV'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MAP: 'MAP'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NEXT: 'NEXT'>, <TokenType.INT128: 'INT128'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VAR: 'VAR'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.COPY: 'COPY'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ROW: 'ROW'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UUID: 'UUID'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DATE32: 'DATE32'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NAME: 'NAME'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CHAR: 'CHAR'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LIST: 'LIST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.KILL: 'KILL'>, <TokenType.USE: 'USE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.IPV4: 'IPV4'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.TIME: 'TIME'>, <TokenType.TRUE: 'TRUE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DESC: 'DESC'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SOME: 'SOME'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ANY: 'ANY'>}
TRIM_TYPES = {'BOTH', 'LEADING', 'TRAILING'}
FUNC_TOKENS = {<TokenType.UTINYINT: 'UTINYINT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT: 'INT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.ENUM: 'ENUM'>, <TokenType.NULL: 'NULL'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ALL: 'ALL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.XML: 'XML'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.INSERT: 'INSERT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BINARY: 'BINARY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.RING: 'RING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.UINT: 'UINT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.YEAR: 'YEAR'>, <TokenType.GLOB: 'GLOB'>, <TokenType.LEFT: 'LEFT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.INET: 'INET'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.POINT: 'POINT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MAP: 'MAP'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.VAR: 'VAR'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.UNION: 'UNION'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ROW: 'ROW'>, <TokenType.UUID: 'UUID'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.DATE32: 'DATE32'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NAME: 'NAME'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CHAR: 'CHAR'>, <TokenType.LIKE: 'LIKE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LIST: 'LIST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.IPV4: 'IPV4'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.TIME: 'TIME'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.XOR: 'XOR'>, <TokenType.SOME: 'SOME'>, <TokenType.ANY: 'ANY'>}
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'>}
TIMES = {<TokenType.TIME: 'TIME'>, <TokenType.TIMETZ: 'TIMETZ'>}
TIMESTAMPS = {<TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>}
SET_OPERATIONS = {<TokenType.UNION: 'UNION'>, <TokenType.INTERSECT: 'INTERSECT'>, <TokenType.EXCEPT: 'EXCEPT'>}
JOIN_METHODS = {<TokenType.POSITIONAL: 'POSITIONAL'>, <TokenType.ASOF: 'ASOF'>, <TokenType.NATURAL: 'NATURAL'>}
JOIN_SIDES = {<TokenType.RIGHT: 'RIGHT'>, <TokenType.FULL: 'FULL'>, <TokenType.LEFT: 'LEFT'>}
JOIN_KINDS = {<TokenType.SEMI: 'SEMI'>, <TokenType.OUTER: 'OUTER'>, <TokenType.ANTI: 'ANTI'>, <TokenType.STRAIGHT_JOIN: 'STRAIGHT_JOIN'>, <TokenType.INNER: 'INNER'>, <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.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.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.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.When'>: <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.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.UPDATE: 'UPDATE'>: <function Parser.<lambda>>, <TokenType.USE: 'USE'>: <function Parser.<lambda>>, <TokenType.SEMICOLON: 'SEMICOLON'>: <function Parser.<lambda>>}
UNARY_PARSERS = {<TokenType.PLUS: 'PLUS'>: <function Parser.<lambda>>, <TokenType.NOT: 'NOT'>: <function Parser.<lambda>>, <TokenType.TILDA: 'TILDA'>: <function Parser.<lambda>>, <TokenType.DASH: 'DASH'>: <function Parser.<lambda>>, <TokenType.PIPE_SLASH: 'PIPE_SLASH'>: <function Parser.<lambda>>, <TokenType.DPIPE_SLASH: 'DPIPE_SLASH'>: <function Parser.<lambda>>}
STRING_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>}
NUMERIC_PARSERS = {<TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>}
PRIMARY_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>, <TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>, <TokenType.INTRODUCER: 'INTRODUCER'>: <function Parser.<lambda>>, <TokenType.NULL: 'NULL'>: <function Parser.<lambda>>, <TokenType.TRUE: 'TRUE'>: <function Parser.<lambda>>, <TokenType.FALSE: 'FALSE'>: <function Parser.<lambda>>, <TokenType.SESSION_PARAMETER: 'SESSION_PARAMETER'>: <function Parser.<lambda>>, <TokenType.STAR: 'STAR'>: <function Parser.<lambda>>}
PLACEHOLDER_PARSERS = {<TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>, <TokenType.PARAMETER: 'PARAMETER'>: <function Parser.<lambda>>, <TokenType.COLON: 'COLON'>: <function Parser.<lambda>>}
RANGE_PARSERS = {<TokenType.AT_GT: 'AT_GT'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.BETWEEN: 'BETWEEN'>: <function Parser.<lambda>>, <TokenType.GLOB: 'GLOB'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.ILIKE: 'ILIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.IN: 'IN'>: <function Parser.<lambda>>, <TokenType.IRLIKE: 'IRLIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.IS: 'IS'>: <function Parser.<lambda>>, <TokenType.LIKE: 'LIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.LT_AT: 'LT_AT'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.OVERLAPS: 'OVERLAPS'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.RLIKE: 'RLIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.SIMILAR_TO: 'SIMILAR_TO'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>}
PROPERTY_PARSERS: Dict[str, Callable] = {'ALLOWED_VALUES': <function Parser.<lambda>>, 'ALGORITHM': <function Parser.<lambda>>, 'AUTO': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'BACKUP': <function Parser.<lambda>>, 'BLOCKCOMPRESSION': <function Parser.<lambda>>, 'CHARSET': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECKSUM': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'CONTAINS': <function Parser.<lambda>>, 'COPY': <function Parser.<lambda>>, 'DATABLOCKSIZE': <function Parser.<lambda>>, 'DATA_DELETION': <function Parser.<lambda>>, 'DEFINER': <function Parser.<lambda>>, 'DETERMINISTIC': <function Parser.<lambda>>, 'DISTRIBUTED': <function Parser.<lambda>>, 'DUPLICATE': <function Parser.<lambda>>, 'DYNAMIC': <function Parser.<lambda>>, 'DISTKEY': <function Parser.<lambda>>, 'DISTSTYLE': <function Parser.<lambda>>, 'EMPTY': <function Parser.<lambda>>, 'ENGINE': <function Parser.<lambda>>, 'EXECUTE': <function Parser.<lambda>>, 'EXTERNAL': <function Parser.<lambda>>, 'FALLBACK': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'FREESPACE': <function Parser.<lambda>>, 'GLOBAL': <function Parser.<lambda>>, 'HEAP': <function Parser.<lambda>>, 'ICEBERG': <function Parser.<lambda>>, 'IMMUTABLE': <function Parser.<lambda>>, 'INHERITS': <function Parser.<lambda>>, 'INPUT': <function Parser.<lambda>>, 'JOURNAL': <function Parser.<lambda>>, 'LANGUAGE': <function Parser.<lambda>>, 'LAYOUT': <function Parser.<lambda>>, 'LIFETIME': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'LOCATION': <function Parser.<lambda>>, 'LOCK': <function Parser.<lambda>>, 'LOCKING': <function Parser.<lambda>>, 'LOG': <function Parser.<lambda>>, 'MATERIALIZED': <function Parser.<lambda>>, 'MERGEBLOCKRATIO': <function Parser.<lambda>>, 'MODIFIES': <function Parser.<lambda>>, 'MULTISET': <function Parser.<lambda>>, 'NO': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'ORDER BY': <function Parser.<lambda>>, 'OUTPUT': <function Parser.<lambda>>, 'PARTITION': <function Parser.<lambda>>, 'PARTITION BY': <function Parser.<lambda>>, 'PARTITIONED BY': <function Parser.<lambda>>, 'PARTITIONED_BY': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'RANGE': <function Parser.<lambda>>, 'READS': <function Parser.<lambda>>, 'REMOTE': <function Parser.<lambda>>, 'RETURNS': <function Parser.<lambda>>, 'STRICT': <function Parser.<lambda>>, 'STREAMING': <function Parser.<lambda>>, 'ROW': <function Parser.<lambda>>, 'ROW_FORMAT': <function Parser.<lambda>>, 'SAMPLE': <function Parser.<lambda>>, 'SECURE': <function Parser.<lambda>>, 'SECURITY': <function Parser.<lambda>>, 'SET': <function Parser.<lambda>>, 'SETTINGS': <function Parser.<lambda>>, 'SHARING': <function Parser.<lambda>>, 'SORTKEY': <function Parser.<lambda>>, 'SOURCE': <function Parser.<lambda>>, 'STABLE': <function Parser.<lambda>>, 'STORED': <function Parser.<lambda>>, 'SYSTEM_VERSIONING': <function Parser.<lambda>>, 'TBLPROPERTIES': <function Parser.<lambda>>, 'TEMP': <function Parser.<lambda>>, 'TEMPORARY': <function Parser.<lambda>>, 'TO': <function Parser.<lambda>>, 'TRANSIENT': <function Parser.<lambda>>, 'TRANSFORM': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'USING': <function Parser.<lambda>>, 'UNLOGGED': <function Parser.<lambda>>, 'VOLATILE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
CONSTRAINT_PARSERS = {'AUTOINCREMENT': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'CASESPECIFIC': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECK': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'COMPRESS': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'NONCLUSTERED': <function Parser.<lambda>>, 'DEFAULT': <function Parser.<lambda>>, 'ENCODE': <function Parser.<lambda>>, 'EPHEMERAL': <function Parser.<lambda>>, 'EXCLUDE': <function Parser.<lambda>>, 'FOREIGN KEY': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'GENERATED': <function Parser.<lambda>>, 'IDENTITY': <function Parser.<lambda>>, 'INLINE': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'NOT': <function Parser.<lambda>>, 'NULL': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'PATH': <function Parser.<lambda>>, 'PERIOD': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'REFERENCES': <function Parser.<lambda>>, 'TITLE': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'UNIQUE': <function Parser.<lambda>>, 'UPPERCASE': <function Parser.<lambda>>, 'WITH': <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 = {'PERIOD', 'UNIQUE', 'PRIMARY KEY', 'FOREIGN KEY', 'CHECK', 'EXCLUDE', 'LIKE'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>, 'NEXT': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STRING: 'STRING'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
KEY_VALUE_DEFINITIONS = (<class 'sqlglot.expressions.Alias'>, <class 'sqlglot.expressions.EQ'>, <class 'sqlglot.expressions.PropertyEQ'>, <class 'sqlglot.expressions.Slice'>)
FUNCTION_PARSERS = {'CAST': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <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>>}
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>>}
DDL_SELECT_TOKENS = {<TokenType.SELECT: 'SELECT'>, <TokenType.WITH: 'WITH'>, <TokenType.L_PAREN: 'L_PAREN'>}
PRE_VOLATILE_TOKENS = {<TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.CREATE: 'CREATE'>}
TRANSACTION_KIND = {'IMMEDIATE', 'EXCLUSIVE', 'DEFERRED'}
TRANSACTION_CHARACTERISTICS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ISOLATION': (('LEVEL', 'REPEATABLE', 'READ'), ('LEVEL', 'READ', 'COMMITTED'), ('LEVEL', 'READ', 'UNCOMITTED'), ('LEVEL', 'SERIALIZABLE')), 'READ': ('WRITE', 'ONLY')}
CONFLICT_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ABORT': (), 'FAIL': (), 'IGNORE': (), 'REPLACE': (), 'ROLLBACK': (), 'UPDATE': (), 'DO': ('NOTHING', 'UPDATE')}
CREATE_SEQUENCE: Dict[str, Sequence[Union[Sequence[str], str]]] = {'SCALE': ('EXTEND', 'NOEXTEND'), 'SHARD': ('EXTEND', 'NOEXTEND'), 'NO': ('CYCLE', 'CACHE', 'MAXVALUE', 'MINVALUE'), 'SESSION': (), 'GLOBAL': (), 'KEEP': (), 'NOKEEP': (), 'ORDER': (), 'NOORDER': (), 'NOCACHE': (), 'CYCLE': (), 'NOCYCLE': (), 'NOMINVALUE': (), 'NOMAXVALUE': (), 'NOSCALE': (), 'NOSHARD': ()}
ISOLATED_LOADING_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'FOR': ('ALL', 'INSERT', 'NONE')}
USABLES: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ROLE': (), 'WAREHOUSE': (), 'DATABASE': (), 'SCHEMA': (), 'CATALOG': ()}
CAST_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'RENAME': ('FIELDS',), 'ADD': ('FIELDS',)}
SCHEMA_BINDING_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'TYPE': ('EVOLUTION',), 'BINDING': (), 'COMPENSATION': (), 'EVOLUTION': ()}
PROCEDURE_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {}
EXECUTE_AS_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'CALLER': (), 'SELF': (), 'OWNER': ()}
KEY_CONSTRAINT_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'NOT': ('ENFORCED',), 'MATCH': ('FULL', 'PARTIAL', 'SIMPLE'), 'INITIALLY': ('DEFERRED', 'IMMEDIATE'), 'DEFERRABLE': (), 'NORELY': ()}
INSERT_ALTERNATIVES = {'REPLACE', 'FAIL', 'ROLLBACK', 'IGNORE', 'ABORT'}
CLONE_KEYWORDS = {'CLONE', 'COPY'}
HISTORICAL_DATA_PREFIX = {'END', 'BEFORE', 'AT'}
HISTORICAL_DATA_KIND = {'STATEMENT', 'OFFSET', 'STREAM', 'TIMESTAMP'}
OPCLASS_FOLLOW_KEYWORDS = {'DESC', 'WITH', 'NULLS', 'ASC'}
OPTYPE_FOLLOW_TOKENS = {<TokenType.COMMA: 'COMMA'>, <TokenType.R_PAREN: 'R_PAREN'>}
TABLE_INDEX_HINT_TOKENS = {<TokenType.IGNORE: 'IGNORE'>, <TokenType.USE: 'USE'>, <TokenType.FORCE: 'FORCE'>}
VIEW_ATTRIBUTES = {'SCHEMABINDING', 'ENCRYPTION', 'VIEW_METADATA'}
WINDOW_ALIAS_TOKENS = {<TokenType.PERCENT: 'PERCENT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.IS: 'IS'>, <TokenType.VIEW: 'VIEW'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT: 'INT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.FALSE: 'FALSE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.NULL: 'NULL'>, <TokenType.TAG: 'TAG'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ALL: 'ALL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.XML: 'XML'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BINARY: 'BINARY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SEMI: 'SEMI'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.ASC: 'ASC'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.RING: 'RING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.UINT: 'UINT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SET: 'SET'>, <TokenType.RENAME: 'RENAME'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.YEAR: 'YEAR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.LOAD: 'LOAD'>, <TokenType.INET: 'INET'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.POINT: 'POINT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DIV: 'DIV'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MAP: 'MAP'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT128: 'INT128'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.CUBE: 'CUBE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VAR: 'VAR'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.FULL: 'FULL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.COPY: 'COPY'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ROW: 'ROW'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UUID: 'UUID'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DATE32: 'DATE32'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NAME: 'NAME'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CHAR: 'CHAR'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LIST: 'LIST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.KILL: 'KILL'>, <TokenType.ASOF: 'ASOF'>, <TokenType.USE: 'USE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.IPV4: 'IPV4'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.TIME: 'TIME'>, <TokenType.TRUE: 'TRUE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DESC: 'DESC'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SOME: 'SOME'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ANY: 'ANY'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'PRECEDING', 'FOLLOWING'}
JSON_KEY_VALUE_SEPARATOR_TOKENS = {<TokenType.IS: 'IS'>, <TokenType.COMMA: 'COMMA'>, <TokenType.COLON: 'COLON'>}
FETCH_TOKENS = {<TokenType.ISNULL: 'ISNULL'>, <TokenType.IS: 'IS'>, <TokenType.VIEW: 'VIEW'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT: 'INT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.FALSE: 'FALSE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.NULL: 'NULL'>, <TokenType.TAG: 'TAG'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ALL: 'ALL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.XML: 'XML'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BINARY: 'BINARY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SEMI: 'SEMI'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.ASC: 'ASC'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.RING: 'RING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.UINT: 'UINT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SET: 'SET'>, <TokenType.RENAME: 'RENAME'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.YEAR: 'YEAR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.LOAD: 'LOAD'>, <TokenType.INET: 'INET'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.POINT: 'POINT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DIV: 'DIV'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MAP: 'MAP'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT128: 'INT128'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.CUBE: 'CUBE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VAR: 'VAR'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.FULL: 'FULL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.COPY: 'COPY'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UUID: 'UUID'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DATE32: 'DATE32'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NAME: 'NAME'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CHAR: 'CHAR'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LIST: 'LIST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.KILL: 'KILL'>, <TokenType.ASOF: 'ASOF'>, <TokenType.USE: 'USE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.IPV4: 'IPV4'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.TIME: 'TIME'>, <TokenType.TRUE: 'TRUE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DESC: 'DESC'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SOME: 'SOME'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ANY: 'ANY'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.UNIQUE: 'UNIQUE'>, <TokenType.KEY: 'KEY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.INDEX: 'INDEX'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.PERCENT: 'PERCENT'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.IS: 'IS'>, <TokenType.VIEW: 'VIEW'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.INT: 'INT'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.FALSE: 'FALSE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.ENUM: 'ENUM'>, <TokenType.NULL: 'NULL'>, <TokenType.TAG: 'TAG'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.ALL: 'ALL'>, <TokenType.IPV6: 'IPV6'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.XML: 'XML'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.RANGE: 'RANGE'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BINARY: 'BINARY'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.END: 'END'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SEMI: 'SEMI'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.ASC: 'ASC'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.RING: 'RING'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.DATE: 'DATE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.INT256: 'INT256'>, <TokenType.UINT: 'UINT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.SET: 'SET'>, <TokenType.RENAME: 'RENAME'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SUPER: 'SUPER'>, <TokenType.YEAR: 'YEAR'>, <TokenType.LEFT: 'LEFT'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.LOAD: 'LOAD'>, <TokenType.INET: 'INET'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.POINT: 'POINT'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.ROWS: 'ROWS'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.DIV: 'DIV'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.MAP: 'MAP'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.BIT: 'BIT'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.NESTED: 'NESTED'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.INT128: 'INT128'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ANTI: 'ANTI'>, <TokenType.CUBE: 'CUBE'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.VAR: 'VAR'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.FULL: 'FULL'>, <TokenType.UINT128: 'UINT128'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.COPY: 'COPY'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.JSONB: 'JSONB'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.MODEL: 'MODEL'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.ROW: 'ROW'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.UUID: 'UUID'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.DATE32: 'DATE32'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.NAME: 'NAME'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.CHAR: 'CHAR'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.MONEY: 'MONEY'>, <TokenType.LIST: 'LIST'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.KILL: 'KILL'>, <TokenType.ASOF: 'ASOF'>, <TokenType.USE: 'USE'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.IPV4: 'IPV4'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.TIME: 'TIME'>, <TokenType.TRUE: 'TRUE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.DESC: 'DESC'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.SOME: 'SOME'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.ANY: 'ANY'>}
SELECT_START_TOKENS = {<TokenType.WITH: 'WITH'>, <TokenType.SELECT: 'SELECT'>, <TokenType.L_PAREN: 'L_PAREN'>}
COPY_INTO_VARLEN_OPTIONS = {'FORMAT_OPTIONS', 'COPY_OPTIONS', 'CREDENTIAL', 'FILE_FORMAT'}
IS_JSON_PREDICATE_KIND = {'SCALAR', 'VALUE', 'OBJECT', 'ARRAY'}
ODBC_DATETIME_LITERALS = {'d': <class 'sqlglot.expressions.Date'>, 't': <class 'sqlglot.expressions.Time'>, 'ts': <class 'sqlglot.expressions.Timestamp'>}
ON_CONDITION_TOKENS = {'EMPTY', 'TRUE', 'FALSE', 'ERROR', 'NULL'}
PRIVILEGE_FOLLOW_TOKENS = {<TokenType.ON: 'ON'>, <TokenType.COMMA: 'COMMA'>, <TokenType.L_PAREN: 'L_PAREN'>}
DESCRIBE_STYLES = {'ANALYZE', 'EXTENDED', 'FORMATTED', 'HISTORY'}
OPERATION_MODIFIERS: Set[str] = set()
STRICT_CAST = True
PREFIXED_PIVOT_COLUMNS = False
IDENTIFY_PIVOT_STRINGS = False
LOG_DEFAULTS_TO_LN = False
ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
TABLESAMPLE_CSV = False
DEFAULT_SAMPLING_METHOD: Optional[str] = None
SET_REQUIRES_ASSIGNMENT_DELIMITER = True
TRIM_PATTERN_FIRST = False
STRING_ALIASES = False
MODIFIERS_ATTACHED_TO_SET_OP = True
SET_OP_MODIFIERS = {'offset', 'limit', 'order'}
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
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):
1394    def reset(self):
1395        self.sql = ""
1396        self.errors = []
1397        self._tokens = []
1398        self._index = 0
1399        self._curr = None
1400        self._next = None
1401        self._prev = None
1402        self._prev_comments = None
def parse( self, raw_tokens: List[sqlglot.tokens.Token], sql: Optional[str] = None) -> List[Optional[sqlglot.expressions.Expression]]:
1404    def parse(
1405        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1406    ) -> t.List[t.Optional[exp.Expression]]:
1407        """
1408        Parses a list of tokens and returns a list of syntax trees, one tree
1409        per parsed SQL statement.
1410
1411        Args:
1412            raw_tokens: The list of tokens.
1413            sql: The original SQL string, used to produce helpful debug messages.
1414
1415        Returns:
1416            The list of the produced syntax trees.
1417        """
1418        return self._parse(
1419            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1420        )

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]]:
1422    def parse_into(
1423        self,
1424        expression_types: exp.IntoType,
1425        raw_tokens: t.List[Token],
1426        sql: t.Optional[str] = None,
1427    ) -> t.List[t.Optional[exp.Expression]]:
1428        """
1429        Parses a list of tokens into a given Expression type. If a collection of Expression
1430        types is given instead, this method will try to parse the token list into each one
1431        of them, stopping at the first for which the parsing succeeds.
1432
1433        Args:
1434            expression_types: The expression type(s) to try and parse the token list into.
1435            raw_tokens: The list of tokens.
1436            sql: The original SQL string, used to produce helpful debug messages.
1437
1438        Returns:
1439            The target Expression.
1440        """
1441        errors = []
1442        for expression_type in ensure_list(expression_types):
1443            parser = self.EXPRESSION_PARSERS.get(expression_type)
1444            if not parser:
1445                raise TypeError(f"No parser registered for {expression_type}")
1446
1447            try:
1448                return self._parse(parser, raw_tokens, sql)
1449            except ParseError as e:
1450                e.errors[0]["into_expression"] = expression_type
1451                errors.append(e)
1452
1453        raise ParseError(
1454            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1455            errors=merge_errors(errors),
1456        ) 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:
1496    def check_errors(self) -> None:
1497        """Logs or raises any found errors, depending on the chosen error level setting."""
1498        if self.error_level == ErrorLevel.WARN:
1499            for error in self.errors:
1500                logger.error(str(error))
1501        elif self.error_level == ErrorLevel.RAISE and self.errors:
1502            raise ParseError(
1503                concat_messages(self.errors, self.max_errors),
1504                errors=merge_errors(self.errors),
1505            )

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:
1507    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1508        """
1509        Appends an error in the list of recorded errors or raises it, depending on the chosen
1510        error level setting.
1511        """
1512        token = token or self._curr or self._prev or Token.string("")
1513        start = token.start
1514        end = token.end + 1
1515        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1516        highlight = self.sql[start:end]
1517        end_context = self.sql[end : end + self.error_message_context]
1518
1519        error = ParseError.new(
1520            f"{message}. Line {token.line}, Col: {token.col}.\n"
1521            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1522            description=message,
1523            line=token.line,
1524            col=token.col,
1525            start_context=start_context,
1526            highlight=highlight,
1527            end_context=end_context,
1528        )
1529
1530        if self.error_level == ErrorLevel.IMMEDIATE:
1531            raise error
1532
1533        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:
1535    def expression(
1536        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1537    ) -> E:
1538        """
1539        Creates a new, validated Expression.
1540
1541        Args:
1542            exp_class: The expression class to instantiate.
1543            comments: An optional list of comments to attach to the expression.
1544            kwargs: The arguments to set for the expression along with their respective values.
1545
1546        Returns:
1547            The target expression.
1548        """
1549        instance = exp_class(**kwargs)
1550        instance.add_comments(comments) if comments else self._add_comments(instance)
1551        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:
1558    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1559        """
1560        Validates an Expression, making sure that all its mandatory arguments are set.
1561
1562        Args:
1563            expression: The expression to validate.
1564            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1565
1566        Returns:
1567            The validated expression.
1568        """
1569        if self.error_level != ErrorLevel.IGNORE:
1570            for error_message in expression.error_messages(args):
1571                self.raise_error(error_message)
1572
1573        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.

errors
sql