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    TCeilFloor = t.TypeVar("TCeilFloor", exp.Ceil, exp.Floor)
  20
  21logger = logging.getLogger("sqlglot")
  22
  23OPTIONS_TYPE = t.Dict[str, t.Sequence[t.Union[t.Sequence[str], str]]]
  24
  25
  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))
  37
  38
  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
  42
  43
  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
  56
  57
  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)
  69
  70
  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)
  74
  75
  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)
  80
  81
  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)
  86
  87
  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
  99
 100
 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)
 110
 111
 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    )
 119
 120
 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
 130
 131
 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)
 142
 143
 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    )
 150
 151
 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)
 154
 155
 156def build_locate_strposition(args: t.List):
 157    return exp.StrPosition(
 158        this=seq_get(args, 1),
 159        substr=seq_get(args, 0),
 160        position=seq_get(args, 2),
 161    )
 162
 163
 164class _Parser(type):
 165    def __new__(cls, clsname, bases, attrs):
 166        klass = super().__new__(cls, clsname, bases, attrs)
 167
 168        klass.SHOW_TRIE = new_trie(key.split(" ") for key in klass.SHOW_PARSERS)
 169        klass.SET_TRIE = new_trie(key.split(" ") for key in klass.SET_PARSERS)
 170
 171        return klass
 172
 173
 174class Parser(metaclass=_Parser):
 175    """
 176    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
 177
 178    Args:
 179        error_level: The desired error level.
 180            Default: ErrorLevel.IMMEDIATE
 181        error_message_context: The amount of context to capture from a query string when displaying
 182            the error message (in number of characters).
 183            Default: 100
 184        max_errors: Maximum number of error messages to include in a raised ParseError.
 185            This is only relevant if error_level is ErrorLevel.RAISE.
 186            Default: 3
 187    """
 188
 189    FUNCTIONS: t.Dict[str, t.Callable] = {
 190        **{name: func.from_arg_list for name, func in exp.FUNCTION_BY_NAME.items()},
 191        **dict.fromkeys(("COALESCE", "IFNULL", "NVL"), build_coalesce),
 192        "ARRAY": lambda args, dialect: exp.Array(expressions=args),
 193        "ARRAYAGG": lambda args, dialect: exp.ArrayAgg(
 194            this=seq_get(args, 0), nulls_excluded=dialect.ARRAY_AGG_INCLUDES_NULLS is None or None
 195        ),
 196        "ARRAY_AGG": lambda args, dialect: exp.ArrayAgg(
 197            this=seq_get(args, 0), nulls_excluded=dialect.ARRAY_AGG_INCLUDES_NULLS is None or None
 198        ),
 199        "CHAR": lambda args: exp.Chr(expressions=args),
 200        "CHR": lambda args: exp.Chr(expressions=args),
 201        "COUNT": lambda args: exp.Count(this=seq_get(args, 0), expressions=args[1:], big_int=True),
 202        "CONCAT": lambda args, dialect: exp.Concat(
 203            expressions=args,
 204            safe=not dialect.STRICT_STRING_CONCAT,
 205            coalesce=dialect.CONCAT_COALESCE,
 206        ),
 207        "CONCAT_WS": lambda args, dialect: exp.ConcatWs(
 208            expressions=args,
 209            safe=not dialect.STRICT_STRING_CONCAT,
 210            coalesce=dialect.CONCAT_COALESCE,
 211        ),
 212        "CONVERT_TIMEZONE": build_convert_timezone,
 213        "DATE_TO_DATE_STR": lambda args: exp.Cast(
 214            this=seq_get(args, 0),
 215            to=exp.DataType(this=exp.DataType.Type.TEXT),
 216        ),
 217        "GENERATE_DATE_ARRAY": lambda args: exp.GenerateDateArray(
 218            start=seq_get(args, 0),
 219            end=seq_get(args, 1),
 220            step=seq_get(args, 2) or exp.Interval(this=exp.Literal.number(1), unit=exp.var("DAY")),
 221        ),
 222        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
 223        "HEX": build_hex,
 224        "JSON_EXTRACT": build_extract_json_with_path(exp.JSONExtract),
 225        "JSON_EXTRACT_SCALAR": build_extract_json_with_path(exp.JSONExtractScalar),
 226        "JSON_EXTRACT_PATH_TEXT": build_extract_json_with_path(exp.JSONExtractScalar),
 227        "LIKE": build_like,
 228        "LOG": build_logarithm,
 229        "LOG2": lambda args: exp.Log(this=exp.Literal.number(2), expression=seq_get(args, 0)),
 230        "LOG10": lambda args: exp.Log(this=exp.Literal.number(10), expression=seq_get(args, 0)),
 231        "LOWER": build_lower,
 232        "LPAD": lambda args: build_pad(args),
 233        "LEFTPAD": lambda args: build_pad(args),
 234        "LTRIM": lambda args: build_trim(args),
 235        "MOD": build_mod,
 236        "RIGHTPAD": lambda args: build_pad(args, is_left=False),
 237        "RPAD": lambda args: build_pad(args, is_left=False),
 238        "RTRIM": lambda args: build_trim(args, is_left=False),
 239        "SCOPE_RESOLUTION": lambda args: exp.ScopeResolution(expression=seq_get(args, 0))
 240        if len(args) != 2
 241        else exp.ScopeResolution(this=seq_get(args, 0), expression=seq_get(args, 1)),
 242        "STRPOS": exp.StrPosition.from_arg_list,
 243        "CHARINDEX": lambda args: build_locate_strposition(args),
 244        "INSTR": exp.StrPosition.from_arg_list,
 245        "LOCATE": lambda args: build_locate_strposition(args),
 246        "TIME_TO_TIME_STR": lambda args: exp.Cast(
 247            this=seq_get(args, 0),
 248            to=exp.DataType(this=exp.DataType.Type.TEXT),
 249        ),
 250        "TO_HEX": build_hex,
 251        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
 252            this=exp.Cast(
 253                this=seq_get(args, 0),
 254                to=exp.DataType(this=exp.DataType.Type.TEXT),
 255            ),
 256            start=exp.Literal.number(1),
 257            length=exp.Literal.number(10),
 258        ),
 259        "UNNEST": lambda args: exp.Unnest(expressions=ensure_list(seq_get(args, 0))),
 260        "UPPER": build_upper,
 261        "VAR_MAP": build_var_map,
 262    }
 263
 264    NO_PAREN_FUNCTIONS = {
 265        TokenType.CURRENT_DATE: exp.CurrentDate,
 266        TokenType.CURRENT_DATETIME: exp.CurrentDate,
 267        TokenType.CURRENT_TIME: exp.CurrentTime,
 268        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
 269        TokenType.CURRENT_USER: exp.CurrentUser,
 270    }
 271
 272    STRUCT_TYPE_TOKENS = {
 273        TokenType.NESTED,
 274        TokenType.OBJECT,
 275        TokenType.STRUCT,
 276        TokenType.UNION,
 277    }
 278
 279    NESTED_TYPE_TOKENS = {
 280        TokenType.ARRAY,
 281        TokenType.LIST,
 282        TokenType.LOWCARDINALITY,
 283        TokenType.MAP,
 284        TokenType.NULLABLE,
 285        TokenType.RANGE,
 286        *STRUCT_TYPE_TOKENS,
 287    }
 288
 289    ENUM_TYPE_TOKENS = {
 290        TokenType.DYNAMIC,
 291        TokenType.ENUM,
 292        TokenType.ENUM8,
 293        TokenType.ENUM16,
 294    }
 295
 296    AGGREGATE_TYPE_TOKENS = {
 297        TokenType.AGGREGATEFUNCTION,
 298        TokenType.SIMPLEAGGREGATEFUNCTION,
 299    }
 300
 301    TYPE_TOKENS = {
 302        TokenType.BIT,
 303        TokenType.BOOLEAN,
 304        TokenType.TINYINT,
 305        TokenType.UTINYINT,
 306        TokenType.SMALLINT,
 307        TokenType.USMALLINT,
 308        TokenType.INT,
 309        TokenType.UINT,
 310        TokenType.BIGINT,
 311        TokenType.UBIGINT,
 312        TokenType.INT128,
 313        TokenType.UINT128,
 314        TokenType.INT256,
 315        TokenType.UINT256,
 316        TokenType.MEDIUMINT,
 317        TokenType.UMEDIUMINT,
 318        TokenType.FIXEDSTRING,
 319        TokenType.FLOAT,
 320        TokenType.DOUBLE,
 321        TokenType.CHAR,
 322        TokenType.NCHAR,
 323        TokenType.VARCHAR,
 324        TokenType.NVARCHAR,
 325        TokenType.BPCHAR,
 326        TokenType.TEXT,
 327        TokenType.MEDIUMTEXT,
 328        TokenType.LONGTEXT,
 329        TokenType.MEDIUMBLOB,
 330        TokenType.LONGBLOB,
 331        TokenType.BINARY,
 332        TokenType.VARBINARY,
 333        TokenType.JSON,
 334        TokenType.JSONB,
 335        TokenType.INTERVAL,
 336        TokenType.TINYBLOB,
 337        TokenType.TINYTEXT,
 338        TokenType.TIME,
 339        TokenType.TIMETZ,
 340        TokenType.TIMESTAMP,
 341        TokenType.TIMESTAMP_S,
 342        TokenType.TIMESTAMP_MS,
 343        TokenType.TIMESTAMP_NS,
 344        TokenType.TIMESTAMPTZ,
 345        TokenType.TIMESTAMPLTZ,
 346        TokenType.TIMESTAMPNTZ,
 347        TokenType.DATETIME,
 348        TokenType.DATETIME2,
 349        TokenType.DATETIME64,
 350        TokenType.SMALLDATETIME,
 351        TokenType.DATE,
 352        TokenType.DATE32,
 353        TokenType.INT4RANGE,
 354        TokenType.INT4MULTIRANGE,
 355        TokenType.INT8RANGE,
 356        TokenType.INT8MULTIRANGE,
 357        TokenType.NUMRANGE,
 358        TokenType.NUMMULTIRANGE,
 359        TokenType.TSRANGE,
 360        TokenType.TSMULTIRANGE,
 361        TokenType.TSTZRANGE,
 362        TokenType.TSTZMULTIRANGE,
 363        TokenType.DATERANGE,
 364        TokenType.DATEMULTIRANGE,
 365        TokenType.DECIMAL,
 366        TokenType.DECIMAL32,
 367        TokenType.DECIMAL64,
 368        TokenType.DECIMAL128,
 369        TokenType.DECIMAL256,
 370        TokenType.UDECIMAL,
 371        TokenType.BIGDECIMAL,
 372        TokenType.UUID,
 373        TokenType.GEOGRAPHY,
 374        TokenType.GEOMETRY,
 375        TokenType.POINT,
 376        TokenType.RING,
 377        TokenType.LINESTRING,
 378        TokenType.MULTILINESTRING,
 379        TokenType.POLYGON,
 380        TokenType.MULTIPOLYGON,
 381        TokenType.HLLSKETCH,
 382        TokenType.HSTORE,
 383        TokenType.PSEUDO_TYPE,
 384        TokenType.SUPER,
 385        TokenType.SERIAL,
 386        TokenType.SMALLSERIAL,
 387        TokenType.BIGSERIAL,
 388        TokenType.XML,
 389        TokenType.YEAR,
 390        TokenType.UNIQUEIDENTIFIER,
 391        TokenType.USERDEFINED,
 392        TokenType.MONEY,
 393        TokenType.SMALLMONEY,
 394        TokenType.ROWVERSION,
 395        TokenType.IMAGE,
 396        TokenType.VARIANT,
 397        TokenType.VECTOR,
 398        TokenType.OBJECT,
 399        TokenType.OBJECT_IDENTIFIER,
 400        TokenType.INET,
 401        TokenType.IPADDRESS,
 402        TokenType.IPPREFIX,
 403        TokenType.IPV4,
 404        TokenType.IPV6,
 405        TokenType.UNKNOWN,
 406        TokenType.NULL,
 407        TokenType.NAME,
 408        TokenType.TDIGEST,
 409        TokenType.DYNAMIC,
 410        *ENUM_TYPE_TOKENS,
 411        *NESTED_TYPE_TOKENS,
 412        *AGGREGATE_TYPE_TOKENS,
 413    }
 414
 415    SIGNED_TO_UNSIGNED_TYPE_TOKEN = {
 416        TokenType.BIGINT: TokenType.UBIGINT,
 417        TokenType.INT: TokenType.UINT,
 418        TokenType.MEDIUMINT: TokenType.UMEDIUMINT,
 419        TokenType.SMALLINT: TokenType.USMALLINT,
 420        TokenType.TINYINT: TokenType.UTINYINT,
 421        TokenType.DECIMAL: TokenType.UDECIMAL,
 422    }
 423
 424    SUBQUERY_PREDICATES = {
 425        TokenType.ANY: exp.Any,
 426        TokenType.ALL: exp.All,
 427        TokenType.EXISTS: exp.Exists,
 428        TokenType.SOME: exp.Any,
 429    }
 430
 431    RESERVED_TOKENS = {
 432        *Tokenizer.SINGLE_TOKENS.values(),
 433        TokenType.SELECT,
 434    } - {TokenType.IDENTIFIER}
 435
 436    DB_CREATABLES = {
 437        TokenType.DATABASE,
 438        TokenType.DICTIONARY,
 439        TokenType.MODEL,
 440        TokenType.NAMESPACE,
 441        TokenType.SCHEMA,
 442        TokenType.SEQUENCE,
 443        TokenType.SINK,
 444        TokenType.SOURCE,
 445        TokenType.STORAGE_INTEGRATION,
 446        TokenType.STREAMLIT,
 447        TokenType.TABLE,
 448        TokenType.TAG,
 449        TokenType.VIEW,
 450        TokenType.WAREHOUSE,
 451    }
 452
 453    CREATABLES = {
 454        TokenType.COLUMN,
 455        TokenType.CONSTRAINT,
 456        TokenType.FOREIGN_KEY,
 457        TokenType.FUNCTION,
 458        TokenType.INDEX,
 459        TokenType.PROCEDURE,
 460        *DB_CREATABLES,
 461    }
 462
 463    ALTERABLES = {
 464        TokenType.INDEX,
 465        TokenType.TABLE,
 466        TokenType.VIEW,
 467    }
 468
 469    # Tokens that can represent identifiers
 470    ID_VAR_TOKENS = {
 471        TokenType.ALL,
 472        TokenType.ATTACH,
 473        TokenType.VAR,
 474        TokenType.ANTI,
 475        TokenType.APPLY,
 476        TokenType.ASC,
 477        TokenType.ASOF,
 478        TokenType.AUTO_INCREMENT,
 479        TokenType.BEGIN,
 480        TokenType.BPCHAR,
 481        TokenType.CACHE,
 482        TokenType.CASE,
 483        TokenType.COLLATE,
 484        TokenType.COMMAND,
 485        TokenType.COMMENT,
 486        TokenType.COMMIT,
 487        TokenType.CONSTRAINT,
 488        TokenType.COPY,
 489        TokenType.CUBE,
 490        TokenType.DEFAULT,
 491        TokenType.DELETE,
 492        TokenType.DESC,
 493        TokenType.DESCRIBE,
 494        TokenType.DETACH,
 495        TokenType.DICTIONARY,
 496        TokenType.DIV,
 497        TokenType.END,
 498        TokenType.EXECUTE,
 499        TokenType.ESCAPE,
 500        TokenType.FALSE,
 501        TokenType.FIRST,
 502        TokenType.FILTER,
 503        TokenType.FINAL,
 504        TokenType.FORMAT,
 505        TokenType.FULL,
 506        TokenType.IDENTIFIER,
 507        TokenType.IS,
 508        TokenType.ISNULL,
 509        TokenType.INTERVAL,
 510        TokenType.KEEP,
 511        TokenType.KILL,
 512        TokenType.LEFT,
 513        TokenType.LIMIT,
 514        TokenType.LOAD,
 515        TokenType.MERGE,
 516        TokenType.NATURAL,
 517        TokenType.NEXT,
 518        TokenType.OFFSET,
 519        TokenType.OPERATOR,
 520        TokenType.ORDINALITY,
 521        TokenType.OVERLAPS,
 522        TokenType.OVERWRITE,
 523        TokenType.PARTITION,
 524        TokenType.PERCENT,
 525        TokenType.PIVOT,
 526        TokenType.PRAGMA,
 527        TokenType.RANGE,
 528        TokenType.RECURSIVE,
 529        TokenType.REFERENCES,
 530        TokenType.REFRESH,
 531        TokenType.RENAME,
 532        TokenType.REPLACE,
 533        TokenType.RIGHT,
 534        TokenType.ROLLUP,
 535        TokenType.ROW,
 536        TokenType.ROWS,
 537        TokenType.SEMI,
 538        TokenType.SET,
 539        TokenType.SETTINGS,
 540        TokenType.SHOW,
 541        TokenType.TEMPORARY,
 542        TokenType.TOP,
 543        TokenType.TRUE,
 544        TokenType.TRUNCATE,
 545        TokenType.UNIQUE,
 546        TokenType.UNNEST,
 547        TokenType.UNPIVOT,
 548        TokenType.UPDATE,
 549        TokenType.USE,
 550        TokenType.VOLATILE,
 551        TokenType.WINDOW,
 552        *CREATABLES,
 553        *SUBQUERY_PREDICATES,
 554        *TYPE_TOKENS,
 555        *NO_PAREN_FUNCTIONS,
 556    }
 557    ID_VAR_TOKENS.remove(TokenType.UNION)
 558
 559    INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
 560
 561    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
 562        TokenType.ANTI,
 563        TokenType.APPLY,
 564        TokenType.ASOF,
 565        TokenType.FULL,
 566        TokenType.LEFT,
 567        TokenType.LOCK,
 568        TokenType.NATURAL,
 569        TokenType.RIGHT,
 570        TokenType.SEMI,
 571        TokenType.WINDOW,
 572    }
 573
 574    ALIAS_TOKENS = ID_VAR_TOKENS
 575
 576    ARRAY_CONSTRUCTORS = {
 577        "ARRAY": exp.Array,
 578        "LIST": exp.List,
 579    }
 580
 581    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
 582
 583    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
 584
 585    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
 586
 587    FUNC_TOKENS = {
 588        TokenType.COLLATE,
 589        TokenType.COMMAND,
 590        TokenType.CURRENT_DATE,
 591        TokenType.CURRENT_DATETIME,
 592        TokenType.CURRENT_TIMESTAMP,
 593        TokenType.CURRENT_TIME,
 594        TokenType.CURRENT_USER,
 595        TokenType.FILTER,
 596        TokenType.FIRST,
 597        TokenType.FORMAT,
 598        TokenType.GLOB,
 599        TokenType.IDENTIFIER,
 600        TokenType.INDEX,
 601        TokenType.ISNULL,
 602        TokenType.ILIKE,
 603        TokenType.INSERT,
 604        TokenType.LIKE,
 605        TokenType.MERGE,
 606        TokenType.NEXT,
 607        TokenType.OFFSET,
 608        TokenType.PRIMARY_KEY,
 609        TokenType.RANGE,
 610        TokenType.REPLACE,
 611        TokenType.RLIKE,
 612        TokenType.ROW,
 613        TokenType.UNNEST,
 614        TokenType.VAR,
 615        TokenType.LEFT,
 616        TokenType.RIGHT,
 617        TokenType.SEQUENCE,
 618        TokenType.DATE,
 619        TokenType.DATETIME,
 620        TokenType.TABLE,
 621        TokenType.TIMESTAMP,
 622        TokenType.TIMESTAMPTZ,
 623        TokenType.TRUNCATE,
 624        TokenType.WINDOW,
 625        TokenType.XOR,
 626        *TYPE_TOKENS,
 627        *SUBQUERY_PREDICATES,
 628    }
 629
 630    CONJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
 631        TokenType.AND: exp.And,
 632    }
 633
 634    ASSIGNMENT: t.Dict[TokenType, t.Type[exp.Expression]] = {
 635        TokenType.COLON_EQ: exp.PropertyEQ,
 636    }
 637
 638    DISJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
 639        TokenType.OR: exp.Or,
 640    }
 641
 642    EQUALITY = {
 643        TokenType.EQ: exp.EQ,
 644        TokenType.NEQ: exp.NEQ,
 645        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
 646    }
 647
 648    COMPARISON = {
 649        TokenType.GT: exp.GT,
 650        TokenType.GTE: exp.GTE,
 651        TokenType.LT: exp.LT,
 652        TokenType.LTE: exp.LTE,
 653    }
 654
 655    BITWISE = {
 656        TokenType.AMP: exp.BitwiseAnd,
 657        TokenType.CARET: exp.BitwiseXor,
 658        TokenType.PIPE: exp.BitwiseOr,
 659    }
 660
 661    TERM = {
 662        TokenType.DASH: exp.Sub,
 663        TokenType.PLUS: exp.Add,
 664        TokenType.MOD: exp.Mod,
 665        TokenType.COLLATE: exp.Collate,
 666    }
 667
 668    FACTOR = {
 669        TokenType.DIV: exp.IntDiv,
 670        TokenType.LR_ARROW: exp.Distance,
 671        TokenType.SLASH: exp.Div,
 672        TokenType.STAR: exp.Mul,
 673    }
 674
 675    EXPONENT: t.Dict[TokenType, t.Type[exp.Expression]] = {}
 676
 677    TIMES = {
 678        TokenType.TIME,
 679        TokenType.TIMETZ,
 680    }
 681
 682    TIMESTAMPS = {
 683        TokenType.TIMESTAMP,
 684        TokenType.TIMESTAMPTZ,
 685        TokenType.TIMESTAMPLTZ,
 686        *TIMES,
 687    }
 688
 689    SET_OPERATIONS = {
 690        TokenType.UNION,
 691        TokenType.INTERSECT,
 692        TokenType.EXCEPT,
 693    }
 694
 695    JOIN_METHODS = {
 696        TokenType.ASOF,
 697        TokenType.NATURAL,
 698        TokenType.POSITIONAL,
 699    }
 700
 701    JOIN_SIDES = {
 702        TokenType.LEFT,
 703        TokenType.RIGHT,
 704        TokenType.FULL,
 705    }
 706
 707    JOIN_KINDS = {
 708        TokenType.ANTI,
 709        TokenType.CROSS,
 710        TokenType.INNER,
 711        TokenType.OUTER,
 712        TokenType.SEMI,
 713        TokenType.STRAIGHT_JOIN,
 714    }
 715
 716    JOIN_HINTS: t.Set[str] = set()
 717
 718    LAMBDAS = {
 719        TokenType.ARROW: lambda self, expressions: self.expression(
 720            exp.Lambda,
 721            this=self._replace_lambda(
 722                self._parse_assignment(),
 723                expressions,
 724            ),
 725            expressions=expressions,
 726        ),
 727        TokenType.FARROW: lambda self, expressions: self.expression(
 728            exp.Kwarg,
 729            this=exp.var(expressions[0].name),
 730            expression=self._parse_assignment(),
 731        ),
 732    }
 733
 734    COLUMN_OPERATORS = {
 735        TokenType.DOT: None,
 736        TokenType.DCOLON: lambda self, this, to: self.expression(
 737            exp.Cast if self.STRICT_CAST else exp.TryCast,
 738            this=this,
 739            to=to,
 740        ),
 741        TokenType.ARROW: lambda self, this, path: self.expression(
 742            exp.JSONExtract,
 743            this=this,
 744            expression=self.dialect.to_json_path(path),
 745            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
 746        ),
 747        TokenType.DARROW: lambda self, this, path: self.expression(
 748            exp.JSONExtractScalar,
 749            this=this,
 750            expression=self.dialect.to_json_path(path),
 751            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
 752        ),
 753        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
 754            exp.JSONBExtract,
 755            this=this,
 756            expression=path,
 757        ),
 758        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
 759            exp.JSONBExtractScalar,
 760            this=this,
 761            expression=path,
 762        ),
 763        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
 764            exp.JSONBContains,
 765            this=this,
 766            expression=key,
 767        ),
 768    }
 769
 770    EXPRESSION_PARSERS = {
 771        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
 772        exp.Column: lambda self: self._parse_column(),
 773        exp.Condition: lambda self: self._parse_assignment(),
 774        exp.DataType: lambda self: self._parse_types(allow_identifiers=False, schema=True),
 775        exp.Expression: lambda self: self._parse_expression(),
 776        exp.From: lambda self: self._parse_from(joins=True),
 777        exp.Group: lambda self: self._parse_group(),
 778        exp.Having: lambda self: self._parse_having(),
 779        exp.Hint: lambda self: self._parse_hint_body(),
 780        exp.Identifier: lambda self: self._parse_id_var(),
 781        exp.Join: lambda self: self._parse_join(),
 782        exp.Lambda: lambda self: self._parse_lambda(),
 783        exp.Lateral: lambda self: self._parse_lateral(),
 784        exp.Limit: lambda self: self._parse_limit(),
 785        exp.Offset: lambda self: self._parse_offset(),
 786        exp.Order: lambda self: self._parse_order(),
 787        exp.Ordered: lambda self: self._parse_ordered(),
 788        exp.Properties: lambda self: self._parse_properties(),
 789        exp.Qualify: lambda self: self._parse_qualify(),
 790        exp.Returning: lambda self: self._parse_returning(),
 791        exp.Select: lambda self: self._parse_select(),
 792        exp.Sort: lambda self: self._parse_sort(exp.Sort, TokenType.SORT_BY),
 793        exp.Table: lambda self: self._parse_table_parts(),
 794        exp.TableAlias: lambda self: self._parse_table_alias(),
 795        exp.Tuple: lambda self: self._parse_value(),
 796        exp.Whens: lambda self: self._parse_when_matched(),
 797        exp.Where: lambda self: self._parse_where(),
 798        exp.Window: lambda self: self._parse_named_window(),
 799        exp.With: lambda self: self._parse_with(),
 800        "JOIN_TYPE": lambda self: self._parse_join_parts(),
 801    }
 802
 803    STATEMENT_PARSERS = {
 804        TokenType.ALTER: lambda self: self._parse_alter(),
 805        TokenType.ANALYZE: lambda self: self._parse_analyze(),
 806        TokenType.BEGIN: lambda self: self._parse_transaction(),
 807        TokenType.CACHE: lambda self: self._parse_cache(),
 808        TokenType.COMMENT: lambda self: self._parse_comment(),
 809        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
 810        TokenType.COPY: lambda self: self._parse_copy(),
 811        TokenType.CREATE: lambda self: self._parse_create(),
 812        TokenType.DELETE: lambda self: self._parse_delete(),
 813        TokenType.DESC: lambda self: self._parse_describe(),
 814        TokenType.DESCRIBE: lambda self: self._parse_describe(),
 815        TokenType.DROP: lambda self: self._parse_drop(),
 816        TokenType.GRANT: lambda self: self._parse_grant(),
 817        TokenType.INSERT: lambda self: self._parse_insert(),
 818        TokenType.KILL: lambda self: self._parse_kill(),
 819        TokenType.LOAD: lambda self: self._parse_load(),
 820        TokenType.MERGE: lambda self: self._parse_merge(),
 821        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
 822        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
 823        TokenType.REFRESH: lambda self: self._parse_refresh(),
 824        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
 825        TokenType.SET: lambda self: self._parse_set(),
 826        TokenType.TRUNCATE: lambda self: self._parse_truncate_table(),
 827        TokenType.UNCACHE: lambda self: self._parse_uncache(),
 828        TokenType.UNPIVOT: lambda self: self._parse_simplified_pivot(is_unpivot=True),
 829        TokenType.UPDATE: lambda self: self._parse_update(),
 830        TokenType.USE: lambda self: self.expression(
 831            exp.Use,
 832            kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
 833            this=self._parse_table(schema=False),
 834        ),
 835        TokenType.SEMICOLON: lambda self: exp.Semicolon(),
 836    }
 837
 838    UNARY_PARSERS = {
 839        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
 840        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
 841        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
 842        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
 843        TokenType.PIPE_SLASH: lambda self: self.expression(exp.Sqrt, this=self._parse_unary()),
 844        TokenType.DPIPE_SLASH: lambda self: self.expression(exp.Cbrt, this=self._parse_unary()),
 845    }
 846
 847    STRING_PARSERS = {
 848        TokenType.HEREDOC_STRING: lambda self, token: self.expression(
 849            exp.RawString, this=token.text
 850        ),
 851        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
 852            exp.National, this=token.text
 853        ),
 854        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
 855        TokenType.STRING: lambda self, token: self.expression(
 856            exp.Literal, this=token.text, is_string=True
 857        ),
 858        TokenType.UNICODE_STRING: lambda self, token: self.expression(
 859            exp.UnicodeString,
 860            this=token.text,
 861            escape=self._match_text_seq("UESCAPE") and self._parse_string(),
 862        ),
 863    }
 864
 865    NUMERIC_PARSERS = {
 866        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
 867        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
 868        TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text),
 869        TokenType.NUMBER: lambda self, token: self.expression(
 870            exp.Literal, this=token.text, is_string=False
 871        ),
 872    }
 873
 874    PRIMARY_PARSERS = {
 875        **STRING_PARSERS,
 876        **NUMERIC_PARSERS,
 877        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
 878        TokenType.NULL: lambda self, _: self.expression(exp.Null),
 879        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
 880        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
 881        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
 882        TokenType.STAR: lambda self, _: self._parse_star_ops(),
 883    }
 884
 885    PLACEHOLDER_PARSERS = {
 886        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
 887        TokenType.PARAMETER: lambda self: self._parse_parameter(),
 888        TokenType.COLON: lambda self: (
 889            self.expression(exp.Placeholder, this=self._prev.text)
 890            if self._match_set(self.ID_VAR_TOKENS)
 891            else None
 892        ),
 893    }
 894
 895    RANGE_PARSERS = {
 896        TokenType.AT_GT: binary_range_parser(exp.ArrayContainsAll),
 897        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
 898        TokenType.GLOB: binary_range_parser(exp.Glob),
 899        TokenType.ILIKE: binary_range_parser(exp.ILike),
 900        TokenType.IN: lambda self, this: self._parse_in(this),
 901        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
 902        TokenType.IS: lambda self, this: self._parse_is(this),
 903        TokenType.LIKE: binary_range_parser(exp.Like),
 904        TokenType.LT_AT: binary_range_parser(exp.ArrayContainsAll, reverse_args=True),
 905        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
 906        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
 907        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
 908        TokenType.FOR: lambda self, this: self._parse_comprehension(this),
 909    }
 910
 911    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
 912        "ALLOWED_VALUES": lambda self: self.expression(
 913            exp.AllowedValuesProperty, expressions=self._parse_csv(self._parse_primary)
 914        ),
 915        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
 916        "AUTO": lambda self: self._parse_auto_property(),
 917        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
 918        "BACKUP": lambda self: self.expression(
 919            exp.BackupProperty, this=self._parse_var(any_token=True)
 920        ),
 921        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
 922        "CHARSET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 923        "CHARACTER SET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 924        "CHECKSUM": lambda self: self._parse_checksum(),
 925        "CLUSTER BY": lambda self: self._parse_cluster(),
 926        "CLUSTERED": lambda self: self._parse_clustered_by(),
 927        "COLLATE": lambda self, **kwargs: self._parse_property_assignment(
 928            exp.CollateProperty, **kwargs
 929        ),
 930        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
 931        "CONTAINS": lambda self: self._parse_contains_property(),
 932        "COPY": lambda self: self._parse_copy_property(),
 933        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
 934        "DATA_DELETION": lambda self: self._parse_data_deletion_property(),
 935        "DEFINER": lambda self: self._parse_definer(),
 936        "DETERMINISTIC": lambda self: self.expression(
 937            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 938        ),
 939        "DISTRIBUTED": lambda self: self._parse_distributed_property(),
 940        "DUPLICATE": lambda self: self._parse_composite_key_property(exp.DuplicateKeyProperty),
 941        "DYNAMIC": lambda self: self.expression(exp.DynamicProperty),
 942        "DISTKEY": lambda self: self._parse_distkey(),
 943        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
 944        "EMPTY": lambda self: self.expression(exp.EmptyProperty),
 945        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
 946        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
 947        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
 948        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
 949        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 950        "FREESPACE": lambda self: self._parse_freespace(),
 951        "GLOBAL": lambda self: self.expression(exp.GlobalProperty),
 952        "HEAP": lambda self: self.expression(exp.HeapProperty),
 953        "ICEBERG": lambda self: self.expression(exp.IcebergProperty),
 954        "IMMUTABLE": lambda self: self.expression(
 955            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 956        ),
 957        "INHERITS": lambda self: self.expression(
 958            exp.InheritsProperty, expressions=self._parse_wrapped_csv(self._parse_table)
 959        ),
 960        "INPUT": lambda self: self.expression(exp.InputModelProperty, this=self._parse_schema()),
 961        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
 962        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
 963        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
 964        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
 965        "LIKE": lambda self: self._parse_create_like(),
 966        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
 967        "LOCK": lambda self: self._parse_locking(),
 968        "LOCKING": lambda self: self._parse_locking(),
 969        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
 970        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
 971        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
 972        "MODIFIES": lambda self: self._parse_modifies_property(),
 973        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
 974        "NO": lambda self: self._parse_no_property(),
 975        "ON": lambda self: self._parse_on_property(),
 976        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
 977        "OUTPUT": lambda self: self.expression(exp.OutputModelProperty, this=self._parse_schema()),
 978        "PARTITION": lambda self: self._parse_partitioned_of(),
 979        "PARTITION BY": lambda self: self._parse_partitioned_by(),
 980        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
 981        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
 982        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
 983        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
 984        "READS": lambda self: self._parse_reads_property(),
 985        "REMOTE": lambda self: self._parse_remote_with_connection(),
 986        "RETURNS": lambda self: self._parse_returns(),
 987        "STRICT": lambda self: self.expression(exp.StrictProperty),
 988        "STREAMING": lambda self: self.expression(exp.StreamingTableProperty),
 989        "ROW": lambda self: self._parse_row(),
 990        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
 991        "SAMPLE": lambda self: self.expression(
 992            exp.SampleProperty, this=self._match_text_seq("BY") and self._parse_bitwise()
 993        ),
 994        "SECURE": lambda self: self.expression(exp.SecureProperty),
 995        "SECURITY": lambda self: self._parse_security(),
 996        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
 997        "SETTINGS": lambda self: self._parse_settings_property(),
 998        "SHARING": lambda self: self._parse_property_assignment(exp.SharingProperty),
 999        "SORTKEY": lambda self: self._parse_sortkey(),
1000        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
1001        "STABLE": lambda self: self.expression(
1002            exp.StabilityProperty, this=exp.Literal.string("STABLE")
1003        ),
1004        "STORED": lambda self: self._parse_stored(),
1005        "SYSTEM_VERSIONING": lambda self: self._parse_system_versioning_property(),
1006        "TBLPROPERTIES": lambda self: self._parse_wrapped_properties(),
1007        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
1008        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
1009        "TO": lambda self: self._parse_to_table(),
1010        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
1011        "TRANSFORM": lambda self: self.expression(
1012            exp.TransformModelProperty, expressions=self._parse_wrapped_csv(self._parse_expression)
1013        ),
1014        "TTL": lambda self: self._parse_ttl(),
1015        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
1016        "UNLOGGED": lambda self: self.expression(exp.UnloggedProperty),
1017        "VOLATILE": lambda self: self._parse_volatile_property(),
1018        "WITH": lambda self: self._parse_with_property(),
1019    }
1020
1021    CONSTRAINT_PARSERS = {
1022        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
1023        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
1024        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
1025        "CHARACTER SET": lambda self: self.expression(
1026            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
1027        ),
1028        "CHECK": lambda self: self.expression(
1029            exp.CheckColumnConstraint,
1030            this=self._parse_wrapped(self._parse_assignment),
1031            enforced=self._match_text_seq("ENFORCED"),
1032        ),
1033        "COLLATE": lambda self: self.expression(
1034            exp.CollateColumnConstraint,
1035            this=self._parse_identifier() or self._parse_column(),
1036        ),
1037        "COMMENT": lambda self: self.expression(
1038            exp.CommentColumnConstraint, this=self._parse_string()
1039        ),
1040        "COMPRESS": lambda self: self._parse_compress(),
1041        "CLUSTERED": lambda self: self.expression(
1042            exp.ClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
1043        ),
1044        "NONCLUSTERED": lambda self: self.expression(
1045            exp.NonClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
1046        ),
1047        "DEFAULT": lambda self: self.expression(
1048            exp.DefaultColumnConstraint, this=self._parse_bitwise()
1049        ),
1050        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
1051        "EPHEMERAL": lambda self: self.expression(
1052            exp.EphemeralColumnConstraint, this=self._parse_bitwise()
1053        ),
1054        "EXCLUDE": lambda self: self.expression(
1055            exp.ExcludeColumnConstraint, this=self._parse_index_params()
1056        ),
1057        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
1058        "FORMAT": lambda self: self.expression(
1059            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
1060        ),
1061        "GENERATED": lambda self: self._parse_generated_as_identity(),
1062        "IDENTITY": lambda self: self._parse_auto_increment(),
1063        "INLINE": lambda self: self._parse_inline(),
1064        "LIKE": lambda self: self._parse_create_like(),
1065        "NOT": lambda self: self._parse_not_constraint(),
1066        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
1067        "ON": lambda self: (
1068            self._match(TokenType.UPDATE)
1069            and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function())
1070        )
1071        or self.expression(exp.OnProperty, this=self._parse_id_var()),
1072        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
1073        "PERIOD": lambda self: self._parse_period_for_system_time(),
1074        "PRIMARY KEY": lambda self: self._parse_primary_key(),
1075        "REFERENCES": lambda self: self._parse_references(match=False),
1076        "TITLE": lambda self: self.expression(
1077            exp.TitleColumnConstraint, this=self._parse_var_or_string()
1078        ),
1079        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
1080        "UNIQUE": lambda self: self._parse_unique(),
1081        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
1082        "WATERMARK": lambda self: self.expression(
1083            exp.WatermarkColumnConstraint,
1084            this=self._match(TokenType.FOR) and self._parse_column(),
1085            expression=self._match(TokenType.ALIAS) and self._parse_disjunction(),
1086        ),
1087        "WITH": lambda self: self.expression(
1088            exp.Properties, expressions=self._parse_wrapped_properties()
1089        ),
1090    }
1091
1092    ALTER_PARSERS = {
1093        "ADD": lambda self: self._parse_alter_table_add(),
1094        "AS": lambda self: self._parse_select(),
1095        "ALTER": lambda self: self._parse_alter_table_alter(),
1096        "CLUSTER BY": lambda self: self._parse_cluster(wrapped=True),
1097        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
1098        "DROP": lambda self: self._parse_alter_table_drop(),
1099        "RENAME": lambda self: self._parse_alter_table_rename(),
1100        "SET": lambda self: self._parse_alter_table_set(),
1101        "SWAP": lambda self: self.expression(
1102            exp.SwapTable, this=self._match(TokenType.WITH) and self._parse_table(schema=True)
1103        ),
1104    }
1105
1106    ALTER_ALTER_PARSERS = {
1107        "DISTKEY": lambda self: self._parse_alter_diststyle(),
1108        "DISTSTYLE": lambda self: self._parse_alter_diststyle(),
1109        "SORTKEY": lambda self: self._parse_alter_sortkey(),
1110        "COMPOUND": lambda self: self._parse_alter_sortkey(compound=True),
1111    }
1112
1113    SCHEMA_UNNAMED_CONSTRAINTS = {
1114        "CHECK",
1115        "EXCLUDE",
1116        "FOREIGN KEY",
1117        "LIKE",
1118        "PERIOD",
1119        "PRIMARY KEY",
1120        "UNIQUE",
1121        "WATERMARK",
1122    }
1123
1124    NO_PAREN_FUNCTION_PARSERS = {
1125        "ANY": lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
1126        "CASE": lambda self: self._parse_case(),
1127        "CONNECT_BY_ROOT": lambda self: self.expression(
1128            exp.ConnectByRoot, this=self._parse_column()
1129        ),
1130        "IF": lambda self: self._parse_if(),
1131    }
1132
1133    INVALID_FUNC_NAME_TOKENS = {
1134        TokenType.IDENTIFIER,
1135        TokenType.STRING,
1136    }
1137
1138    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
1139
1140    KEY_VALUE_DEFINITIONS = (exp.Alias, exp.EQ, exp.PropertyEQ, exp.Slice)
1141
1142    FUNCTION_PARSERS = {
1143        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
1144        "CEIL": lambda self: self._parse_ceil_floor(exp.Ceil),
1145        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
1146        "DECODE": lambda self: self._parse_decode(),
1147        "EXTRACT": lambda self: self._parse_extract(),
1148        "FLOOR": lambda self: self._parse_ceil_floor(exp.Floor),
1149        "GAP_FILL": lambda self: self._parse_gap_fill(),
1150        "JSON_OBJECT": lambda self: self._parse_json_object(),
1151        "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
1152        "JSON_TABLE": lambda self: self._parse_json_table(),
1153        "MATCH": lambda self: self._parse_match_against(),
1154        "NORMALIZE": lambda self: self._parse_normalize(),
1155        "OPENJSON": lambda self: self._parse_open_json(),
1156        "OVERLAY": lambda self: self._parse_overlay(),
1157        "POSITION": lambda self: self._parse_position(),
1158        "PREDICT": lambda self: self._parse_predict(),
1159        "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
1160        "STRING_AGG": lambda self: self._parse_string_agg(),
1161        "SUBSTRING": lambda self: self._parse_substring(),
1162        "TRIM": lambda self: self._parse_trim(),
1163        "TRY_CAST": lambda self: self._parse_cast(False, safe=True),
1164        "TRY_CONVERT": lambda self: self._parse_convert(False, safe=True),
1165        "XMLELEMENT": lambda self: self.expression(
1166            exp.XMLElement,
1167            this=self._match_text_seq("NAME") and self._parse_id_var(),
1168            expressions=self._match(TokenType.COMMA) and self._parse_csv(self._parse_expression),
1169        ),
1170        "XMLTABLE": lambda self: self._parse_xml_table(),
1171    }
1172
1173    QUERY_MODIFIER_PARSERS = {
1174        TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
1175        TokenType.PREWHERE: lambda self: ("prewhere", self._parse_prewhere()),
1176        TokenType.WHERE: lambda self: ("where", self._parse_where()),
1177        TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
1178        TokenType.HAVING: lambda self: ("having", self._parse_having()),
1179        TokenType.QUALIFY: lambda self: ("qualify", self._parse_qualify()),
1180        TokenType.WINDOW: lambda self: ("windows", self._parse_window_clause()),
1181        TokenType.ORDER_BY: lambda self: ("order", self._parse_order()),
1182        TokenType.LIMIT: lambda self: ("limit", self._parse_limit()),
1183        TokenType.FETCH: lambda self: ("limit", self._parse_limit()),
1184        TokenType.OFFSET: lambda self: ("offset", self._parse_offset()),
1185        TokenType.FOR: lambda self: ("locks", self._parse_locks()),
1186        TokenType.LOCK: lambda self: ("locks", self._parse_locks()),
1187        TokenType.TABLE_SAMPLE: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
1188        TokenType.USING: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
1189        TokenType.CLUSTER_BY: lambda self: (
1190            "cluster",
1191            self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
1192        ),
1193        TokenType.DISTRIBUTE_BY: lambda self: (
1194            "distribute",
1195            self._parse_sort(exp.Distribute, TokenType.DISTRIBUTE_BY),
1196        ),
1197        TokenType.SORT_BY: lambda self: ("sort", self._parse_sort(exp.Sort, TokenType.SORT_BY)),
1198        TokenType.CONNECT_BY: lambda self: ("connect", self._parse_connect(skip_start_token=True)),
1199        TokenType.START_WITH: lambda self: ("connect", self._parse_connect()),
1200    }
1201
1202    SET_PARSERS = {
1203        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
1204        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
1205        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
1206        "TRANSACTION": lambda self: self._parse_set_transaction(),
1207    }
1208
1209    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
1210
1211    TYPE_LITERAL_PARSERS = {
1212        exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
1213    }
1214
1215    TYPE_CONVERTERS: t.Dict[exp.DataType.Type, t.Callable[[exp.DataType], exp.DataType]] = {}
1216
1217    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
1218
1219    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
1220
1221    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
1222    TRANSACTION_CHARACTERISTICS: OPTIONS_TYPE = {
1223        "ISOLATION": (
1224            ("LEVEL", "REPEATABLE", "READ"),
1225            ("LEVEL", "READ", "COMMITTED"),
1226            ("LEVEL", "READ", "UNCOMITTED"),
1227            ("LEVEL", "SERIALIZABLE"),
1228        ),
1229        "READ": ("WRITE", "ONLY"),
1230    }
1231
1232    CONFLICT_ACTIONS: OPTIONS_TYPE = dict.fromkeys(
1233        ("ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK", "UPDATE"), tuple()
1234    )
1235    CONFLICT_ACTIONS["DO"] = ("NOTHING", "UPDATE")
1236
1237    CREATE_SEQUENCE: OPTIONS_TYPE = {
1238        "SCALE": ("EXTEND", "NOEXTEND"),
1239        "SHARD": ("EXTEND", "NOEXTEND"),
1240        "NO": ("CYCLE", "CACHE", "MAXVALUE", "MINVALUE"),
1241        **dict.fromkeys(
1242            (
1243                "SESSION",
1244                "GLOBAL",
1245                "KEEP",
1246                "NOKEEP",
1247                "ORDER",
1248                "NOORDER",
1249                "NOCACHE",
1250                "CYCLE",
1251                "NOCYCLE",
1252                "NOMINVALUE",
1253                "NOMAXVALUE",
1254                "NOSCALE",
1255                "NOSHARD",
1256            ),
1257            tuple(),
1258        ),
1259    }
1260
1261    ISOLATED_LOADING_OPTIONS: OPTIONS_TYPE = {"FOR": ("ALL", "INSERT", "NONE")}
1262
1263    USABLES: OPTIONS_TYPE = dict.fromkeys(
1264        ("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA", "CATALOG"), tuple()
1265    )
1266
1267    CAST_ACTIONS: OPTIONS_TYPE = dict.fromkeys(("RENAME", "ADD"), ("FIELDS",))
1268
1269    SCHEMA_BINDING_OPTIONS: OPTIONS_TYPE = {
1270        "TYPE": ("EVOLUTION",),
1271        **dict.fromkeys(("BINDING", "COMPENSATION", "EVOLUTION"), tuple()),
1272    }
1273
1274    PROCEDURE_OPTIONS: OPTIONS_TYPE = {}
1275
1276    EXECUTE_AS_OPTIONS: OPTIONS_TYPE = dict.fromkeys(("CALLER", "SELF", "OWNER"), tuple())
1277
1278    KEY_CONSTRAINT_OPTIONS: OPTIONS_TYPE = {
1279        "NOT": ("ENFORCED",),
1280        "MATCH": (
1281            "FULL",
1282            "PARTIAL",
1283            "SIMPLE",
1284        ),
1285        "INITIALLY": ("DEFERRED", "IMMEDIATE"),
1286        **dict.fromkeys(("DEFERRABLE", "NORELY"), tuple()),
1287    }
1288
1289    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
1290
1291    CLONE_KEYWORDS = {"CLONE", "COPY"}
1292    HISTORICAL_DATA_PREFIX = {"AT", "BEFORE", "END"}
1293    HISTORICAL_DATA_KIND = {"TIMESTAMP", "OFFSET", "STATEMENT", "STREAM"}
1294
1295    OPCLASS_FOLLOW_KEYWORDS = {"ASC", "DESC", "NULLS", "WITH"}
1296
1297    OPTYPE_FOLLOW_TOKENS = {TokenType.COMMA, TokenType.R_PAREN}
1298
1299    TABLE_INDEX_HINT_TOKENS = {TokenType.FORCE, TokenType.IGNORE, TokenType.USE}
1300
1301    VIEW_ATTRIBUTES = {"ENCRYPTION", "SCHEMABINDING", "VIEW_METADATA"}
1302
1303    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
1304    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
1305    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
1306
1307    JSON_KEY_VALUE_SEPARATOR_TOKENS = {TokenType.COLON, TokenType.COMMA, TokenType.IS}
1308
1309    FETCH_TOKENS = ID_VAR_TOKENS - {TokenType.ROW, TokenType.ROWS, TokenType.PERCENT}
1310
1311    ADD_CONSTRAINT_TOKENS = {
1312        TokenType.CONSTRAINT,
1313        TokenType.FOREIGN_KEY,
1314        TokenType.INDEX,
1315        TokenType.KEY,
1316        TokenType.PRIMARY_KEY,
1317        TokenType.UNIQUE,
1318    }
1319
1320    DISTINCT_TOKENS = {TokenType.DISTINCT}
1321
1322    NULL_TOKENS = {TokenType.NULL}
1323
1324    UNNEST_OFFSET_ALIAS_TOKENS = ID_VAR_TOKENS - SET_OPERATIONS
1325
1326    SELECT_START_TOKENS = {TokenType.L_PAREN, TokenType.WITH, TokenType.SELECT}
1327
1328    COPY_INTO_VARLEN_OPTIONS = {"FILE_FORMAT", "COPY_OPTIONS", "FORMAT_OPTIONS", "CREDENTIAL"}
1329
1330    IS_JSON_PREDICATE_KIND = {"VALUE", "SCALAR", "ARRAY", "OBJECT"}
1331
1332    ODBC_DATETIME_LITERALS = {
1333        "d": exp.Date,
1334        "t": exp.Time,
1335        "ts": exp.Timestamp,
1336    }
1337
1338    ON_CONDITION_TOKENS = {"ERROR", "NULL", "TRUE", "FALSE", "EMPTY"}
1339
1340    PRIVILEGE_FOLLOW_TOKENS = {TokenType.ON, TokenType.COMMA, TokenType.L_PAREN}
1341
1342    # The style options for the DESCRIBE statement
1343    DESCRIBE_STYLES = {"ANALYZE", "EXTENDED", "FORMATTED", "HISTORY"}
1344
1345    # The style options for the ANALYZE statement
1346    ANALYZE_STYLES = {
1347        "BUFFER_USAGE_LIMIT",
1348        "FULL",
1349        "LOCAL",
1350        "NO_WRITE_TO_BINLOG",
1351        "SAMPLE",
1352        "SKIP_LOCKED",
1353        "VERBOSE",
1354    }
1355
1356    ANALYZE_EXPRESSION_PARSERS = {
1357        "ALL": lambda self: self._parse_analyze_columns(),
1358        "COMPUTE": lambda self: self._parse_analyze_statistics(),
1359        "DELETE": lambda self: self._parse_analyze_delete(),
1360        "DROP": lambda self: self._parse_analyze_histogram(),
1361        "ESTIMATE": lambda self: self._parse_analyze_statistics(),
1362        "LIST": lambda self: self._parse_analyze_list(),
1363        "PREDICATE": lambda self: self._parse_analyze_columns(),
1364        "UPDATE": lambda self: self._parse_analyze_histogram(),
1365        "VALIDATE": lambda self: self._parse_analyze_validate(),
1366    }
1367
1368    PARTITION_KEYWORDS = {"PARTITION", "SUBPARTITION"}
1369
1370    AMBIGUOUS_ALIAS_TOKENS = (TokenType.LIMIT, TokenType.OFFSET)
1371
1372    OPERATION_MODIFIERS: t.Set[str] = set()
1373
1374    STRICT_CAST = True
1375
1376    PREFIXED_PIVOT_COLUMNS = False
1377    IDENTIFY_PIVOT_STRINGS = False
1378
1379    LOG_DEFAULTS_TO_LN = False
1380
1381    # Whether ADD is present for each column added by ALTER TABLE
1382    ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
1383
1384    # Whether the table sample clause expects CSV syntax
1385    TABLESAMPLE_CSV = False
1386
1387    # The default method used for table sampling
1388    DEFAULT_SAMPLING_METHOD: t.Optional[str] = None
1389
1390    # Whether the SET command needs a delimiter (e.g. "=") for assignments
1391    SET_REQUIRES_ASSIGNMENT_DELIMITER = True
1392
1393    # Whether the TRIM function expects the characters to trim as its first argument
1394    TRIM_PATTERN_FIRST = False
1395
1396    # Whether string aliases are supported `SELECT COUNT(*) 'count'`
1397    STRING_ALIASES = False
1398
1399    # Whether query modifiers such as LIMIT are attached to the UNION node (vs its right operand)
1400    MODIFIERS_ATTACHED_TO_SET_OP = True
1401    SET_OP_MODIFIERS = {"order", "limit", "offset"}
1402
1403    # Whether to parse IF statements that aren't followed by a left parenthesis as commands
1404    NO_PAREN_IF_COMMANDS = True
1405
1406    # Whether the -> and ->> operators expect documents of type JSON (e.g. Postgres)
1407    JSON_ARROWS_REQUIRE_JSON_TYPE = False
1408
1409    # Whether the `:` operator is used to extract a value from a VARIANT column
1410    COLON_IS_VARIANT_EXTRACT = False
1411
1412    # Whether or not a VALUES keyword needs to be followed by '(' to form a VALUES clause.
1413    # If this is True and '(' is not found, the keyword will be treated as an identifier
1414    VALUES_FOLLOWED_BY_PAREN = True
1415
1416    # Whether implicit unnesting is supported, e.g. SELECT 1 FROM y.z AS z, z.a (Redshift)
1417    SUPPORTS_IMPLICIT_UNNEST = False
1418
1419    # Whether or not interval spans are supported, INTERVAL 1 YEAR TO MONTHS
1420    INTERVAL_SPANS = True
1421
1422    # Whether a PARTITION clause can follow a table reference
1423    SUPPORTS_PARTITION_SELECTION = False
1424
1425    # Whether the `name AS expr` schema/column constraint requires parentheses around `expr`
1426    WRAPPED_TRANSFORM_COLUMN_CONSTRAINT = True
1427
1428    # Whether the 'AS' keyword is optional in the CTE definition syntax
1429    OPTIONAL_ALIAS_TOKEN_CTE = True
1430
1431    __slots__ = (
1432        "error_level",
1433        "error_message_context",
1434        "max_errors",
1435        "dialect",
1436        "sql",
1437        "errors",
1438        "_tokens",
1439        "_index",
1440        "_curr",
1441        "_next",
1442        "_prev",
1443        "_prev_comments",
1444    )
1445
1446    # Autofilled
1447    SHOW_TRIE: t.Dict = {}
1448    SET_TRIE: t.Dict = {}
1449
1450    def __init__(
1451        self,
1452        error_level: t.Optional[ErrorLevel] = None,
1453        error_message_context: int = 100,
1454        max_errors: int = 3,
1455        dialect: DialectType = None,
1456    ):
1457        from sqlglot.dialects import Dialect
1458
1459        self.error_level = error_level or ErrorLevel.IMMEDIATE
1460        self.error_message_context = error_message_context
1461        self.max_errors = max_errors
1462        self.dialect = Dialect.get_or_raise(dialect)
1463        self.reset()
1464
1465    def reset(self):
1466        self.sql = ""
1467        self.errors = []
1468        self._tokens = []
1469        self._index = 0
1470        self._curr = None
1471        self._next = None
1472        self._prev = None
1473        self._prev_comments = None
1474
1475    def parse(
1476        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1477    ) -> t.List[t.Optional[exp.Expression]]:
1478        """
1479        Parses a list of tokens and returns a list of syntax trees, one tree
1480        per parsed SQL statement.
1481
1482        Args:
1483            raw_tokens: The list of tokens.
1484            sql: The original SQL string, used to produce helpful debug messages.
1485
1486        Returns:
1487            The list of the produced syntax trees.
1488        """
1489        return self._parse(
1490            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1491        )
1492
1493    def parse_into(
1494        self,
1495        expression_types: exp.IntoType,
1496        raw_tokens: t.List[Token],
1497        sql: t.Optional[str] = None,
1498    ) -> t.List[t.Optional[exp.Expression]]:
1499        """
1500        Parses a list of tokens into a given Expression type. If a collection of Expression
1501        types is given instead, this method will try to parse the token list into each one
1502        of them, stopping at the first for which the parsing succeeds.
1503
1504        Args:
1505            expression_types: The expression type(s) to try and parse the token list into.
1506            raw_tokens: The list of tokens.
1507            sql: The original SQL string, used to produce helpful debug messages.
1508
1509        Returns:
1510            The target Expression.
1511        """
1512        errors = []
1513        for expression_type in ensure_list(expression_types):
1514            parser = self.EXPRESSION_PARSERS.get(expression_type)
1515            if not parser:
1516                raise TypeError(f"No parser registered for {expression_type}")
1517
1518            try:
1519                return self._parse(parser, raw_tokens, sql)
1520            except ParseError as e:
1521                e.errors[0]["into_expression"] = expression_type
1522                errors.append(e)
1523
1524        raise ParseError(
1525            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1526            errors=merge_errors(errors),
1527        ) from errors[-1]
1528
1529    def _parse(
1530        self,
1531        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
1532        raw_tokens: t.List[Token],
1533        sql: t.Optional[str] = None,
1534    ) -> t.List[t.Optional[exp.Expression]]:
1535        self.reset()
1536        self.sql = sql or ""
1537
1538        total = len(raw_tokens)
1539        chunks: t.List[t.List[Token]] = [[]]
1540
1541        for i, token in enumerate(raw_tokens):
1542            if token.token_type == TokenType.SEMICOLON:
1543                if token.comments:
1544                    chunks.append([token])
1545
1546                if i < total - 1:
1547                    chunks.append([])
1548            else:
1549                chunks[-1].append(token)
1550
1551        expressions = []
1552
1553        for tokens in chunks:
1554            self._index = -1
1555            self._tokens = tokens
1556            self._advance()
1557
1558            expressions.append(parse_method(self))
1559
1560            if self._index < len(self._tokens):
1561                self.raise_error("Invalid expression / Unexpected token")
1562
1563            self.check_errors()
1564
1565        return expressions
1566
1567    def check_errors(self) -> None:
1568        """Logs or raises any found errors, depending on the chosen error level setting."""
1569        if self.error_level == ErrorLevel.WARN:
1570            for error in self.errors:
1571                logger.error(str(error))
1572        elif self.error_level == ErrorLevel.RAISE and self.errors:
1573            raise ParseError(
1574                concat_messages(self.errors, self.max_errors),
1575                errors=merge_errors(self.errors),
1576            )
1577
1578    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1579        """
1580        Appends an error in the list of recorded errors or raises it, depending on the chosen
1581        error level setting.
1582        """
1583        token = token or self._curr or self._prev or Token.string("")
1584        start = token.start
1585        end = token.end + 1
1586        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1587        highlight = self.sql[start:end]
1588        end_context = self.sql[end : end + self.error_message_context]
1589
1590        error = ParseError.new(
1591            f"{message}. Line {token.line}, Col: {token.col}.\n"
1592            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1593            description=message,
1594            line=token.line,
1595            col=token.col,
1596            start_context=start_context,
1597            highlight=highlight,
1598            end_context=end_context,
1599        )
1600
1601        if self.error_level == ErrorLevel.IMMEDIATE:
1602            raise error
1603
1604        self.errors.append(error)
1605
1606    def expression(
1607        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1608    ) -> E:
1609        """
1610        Creates a new, validated Expression.
1611
1612        Args:
1613            exp_class: The expression class to instantiate.
1614            comments: An optional list of comments to attach to the expression.
1615            kwargs: The arguments to set for the expression along with their respective values.
1616
1617        Returns:
1618            The target expression.
1619        """
1620        instance = exp_class(**kwargs)
1621        instance.add_comments(comments) if comments else self._add_comments(instance)
1622        return self.validate_expression(instance)
1623
1624    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
1625        if expression and self._prev_comments:
1626            expression.add_comments(self._prev_comments)
1627            self._prev_comments = None
1628
1629    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1630        """
1631        Validates an Expression, making sure that all its mandatory arguments are set.
1632
1633        Args:
1634            expression: The expression to validate.
1635            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1636
1637        Returns:
1638            The validated expression.
1639        """
1640        if self.error_level != ErrorLevel.IGNORE:
1641            for error_message in expression.error_messages(args):
1642                self.raise_error(error_message)
1643
1644        return expression
1645
1646    def _find_sql(self, start: Token, end: Token) -> str:
1647        return self.sql[start.start : end.end + 1]
1648
1649    def _is_connected(self) -> bool:
1650        return self._prev and self._curr and self._prev.end + 1 == self._curr.start
1651
1652    def _advance(self, times: int = 1) -> None:
1653        self._index += times
1654        self._curr = seq_get(self._tokens, self._index)
1655        self._next = seq_get(self._tokens, self._index + 1)
1656
1657        if self._index > 0:
1658            self._prev = self._tokens[self._index - 1]
1659            self._prev_comments = self._prev.comments
1660        else:
1661            self._prev = None
1662            self._prev_comments = None
1663
1664    def _retreat(self, index: int) -> None:
1665        if index != self._index:
1666            self._advance(index - self._index)
1667
1668    def _warn_unsupported(self) -> None:
1669        if len(self._tokens) <= 1:
1670            return
1671
1672        # We use _find_sql because self.sql may comprise multiple chunks, and we're only
1673        # interested in emitting a warning for the one being currently processed.
1674        sql = self._find_sql(self._tokens[0], self._tokens[-1])[: self.error_message_context]
1675
1676        logger.warning(
1677            f"'{sql}' contains unsupported syntax. Falling back to parsing as a 'Command'."
1678        )
1679
1680    def _parse_command(self) -> exp.Command:
1681        self._warn_unsupported()
1682        return self.expression(
1683            exp.Command,
1684            comments=self._prev_comments,
1685            this=self._prev.text.upper(),
1686            expression=self._parse_string(),
1687        )
1688
1689    def _try_parse(self, parse_method: t.Callable[[], T], retreat: bool = False) -> t.Optional[T]:
1690        """
1691        Attemps to backtrack if a parse function that contains a try/catch internally raises an error.
1692        This behavior can be different depending on the uset-set ErrorLevel, so _try_parse aims to
1693        solve this by setting & resetting the parser state accordingly
1694        """
1695        index = self._index
1696        error_level = self.error_level
1697
1698        self.error_level = ErrorLevel.IMMEDIATE
1699        try:
1700            this = parse_method()
1701        except ParseError:
1702            this = None
1703        finally:
1704            if not this or retreat:
1705                self._retreat(index)
1706            self.error_level = error_level
1707
1708        return this
1709
1710    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
1711        start = self._prev
1712        exists = self._parse_exists() if allow_exists else None
1713
1714        self._match(TokenType.ON)
1715
1716        materialized = self._match_text_seq("MATERIALIZED")
1717        kind = self._match_set(self.CREATABLES) and self._prev
1718        if not kind:
1719            return self._parse_as_command(start)
1720
1721        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1722            this = self._parse_user_defined_function(kind=kind.token_type)
1723        elif kind.token_type == TokenType.TABLE:
1724            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
1725        elif kind.token_type == TokenType.COLUMN:
1726            this = self._parse_column()
1727        else:
1728            this = self._parse_id_var()
1729
1730        self._match(TokenType.IS)
1731
1732        return self.expression(
1733            exp.Comment,
1734            this=this,
1735            kind=kind.text,
1736            expression=self._parse_string(),
1737            exists=exists,
1738            materialized=materialized,
1739        )
1740
1741    def _parse_to_table(
1742        self,
1743    ) -> exp.ToTableProperty:
1744        table = self._parse_table_parts(schema=True)
1745        return self.expression(exp.ToTableProperty, this=table)
1746
1747    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
1748    def _parse_ttl(self) -> exp.Expression:
1749        def _parse_ttl_action() -> t.Optional[exp.Expression]:
1750            this = self._parse_bitwise()
1751
1752            if self._match_text_seq("DELETE"):
1753                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
1754            if self._match_text_seq("RECOMPRESS"):
1755                return self.expression(
1756                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
1757                )
1758            if self._match_text_seq("TO", "DISK"):
1759                return self.expression(
1760                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
1761                )
1762            if self._match_text_seq("TO", "VOLUME"):
1763                return self.expression(
1764                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
1765                )
1766
1767            return this
1768
1769        expressions = self._parse_csv(_parse_ttl_action)
1770        where = self._parse_where()
1771        group = self._parse_group()
1772
1773        aggregates = None
1774        if group and self._match(TokenType.SET):
1775            aggregates = self._parse_csv(self._parse_set_item)
1776
1777        return self.expression(
1778            exp.MergeTreeTTL,
1779            expressions=expressions,
1780            where=where,
1781            group=group,
1782            aggregates=aggregates,
1783        )
1784
1785    def _parse_statement(self) -> t.Optional[exp.Expression]:
1786        if self._curr is None:
1787            return None
1788
1789        if self._match_set(self.STATEMENT_PARSERS):
1790            comments = self._prev_comments
1791            stmt = self.STATEMENT_PARSERS[self._prev.token_type](self)
1792            stmt.add_comments(comments, prepend=True)
1793            return stmt
1794
1795        if self._match_set(self.dialect.tokenizer.COMMANDS):
1796            return self._parse_command()
1797
1798        expression = self._parse_expression()
1799        expression = self._parse_set_operations(expression) if expression else self._parse_select()
1800        return self._parse_query_modifiers(expression)
1801
1802    def _parse_drop(self, exists: bool = False) -> exp.Drop | exp.Command:
1803        start = self._prev
1804        temporary = self._match(TokenType.TEMPORARY)
1805        materialized = self._match_text_seq("MATERIALIZED")
1806
1807        kind = self._match_set(self.CREATABLES) and self._prev.text.upper()
1808        if not kind:
1809            return self._parse_as_command(start)
1810
1811        concurrently = self._match_text_seq("CONCURRENTLY")
1812        if_exists = exists or self._parse_exists()
1813
1814        if kind == "COLUMN":
1815            this = self._parse_column()
1816        else:
1817            this = self._parse_table_parts(
1818                schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
1819            )
1820
1821        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
1822
1823        if self._match(TokenType.L_PAREN, advance=False):
1824            expressions = self._parse_wrapped_csv(self._parse_types)
1825        else:
1826            expressions = None
1827
1828        return self.expression(
1829            exp.Drop,
1830            exists=if_exists,
1831            this=this,
1832            expressions=expressions,
1833            kind=self.dialect.CREATABLE_KIND_MAPPING.get(kind) or kind,
1834            temporary=temporary,
1835            materialized=materialized,
1836            cascade=self._match_text_seq("CASCADE"),
1837            constraints=self._match_text_seq("CONSTRAINTS"),
1838            purge=self._match_text_seq("PURGE"),
1839            cluster=cluster,
1840            concurrently=concurrently,
1841        )
1842
1843    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
1844        return (
1845            self._match_text_seq("IF")
1846            and (not not_ or self._match(TokenType.NOT))
1847            and self._match(TokenType.EXISTS)
1848        )
1849
1850    def _parse_create(self) -> exp.Create | exp.Command:
1851        # Note: this can't be None because we've matched a statement parser
1852        start = self._prev
1853
1854        replace = (
1855            start.token_type == TokenType.REPLACE
1856            or self._match_pair(TokenType.OR, TokenType.REPLACE)
1857            or self._match_pair(TokenType.OR, TokenType.ALTER)
1858        )
1859        refresh = self._match_pair(TokenType.OR, TokenType.REFRESH)
1860
1861        unique = self._match(TokenType.UNIQUE)
1862
1863        if self._match_text_seq("CLUSTERED", "COLUMNSTORE"):
1864            clustered = True
1865        elif self._match_text_seq("NONCLUSTERED", "COLUMNSTORE") or self._match_text_seq(
1866            "COLUMNSTORE"
1867        ):
1868            clustered = False
1869        else:
1870            clustered = None
1871
1872        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
1873            self._advance()
1874
1875        properties = None
1876        create_token = self._match_set(self.CREATABLES) and self._prev
1877
1878        if not create_token:
1879            # exp.Properties.Location.POST_CREATE
1880            properties = self._parse_properties()
1881            create_token = self._match_set(self.CREATABLES) and self._prev
1882
1883            if not properties or not create_token:
1884                return self._parse_as_command(start)
1885
1886        concurrently = self._match_text_seq("CONCURRENTLY")
1887        exists = self._parse_exists(not_=True)
1888        this = None
1889        expression: t.Optional[exp.Expression] = None
1890        indexes = None
1891        no_schema_binding = None
1892        begin = None
1893        end = None
1894        clone = None
1895
1896        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
1897            nonlocal properties
1898            if properties and temp_props:
1899                properties.expressions.extend(temp_props.expressions)
1900            elif temp_props:
1901                properties = temp_props
1902
1903        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1904            this = self._parse_user_defined_function(kind=create_token.token_type)
1905
1906            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
1907            extend_props(self._parse_properties())
1908
1909            expression = self._match(TokenType.ALIAS) and self._parse_heredoc()
1910            extend_props(self._parse_properties())
1911
1912            if not expression:
1913                if self._match(TokenType.COMMAND):
1914                    expression = self._parse_as_command(self._prev)
1915                else:
1916                    begin = self._match(TokenType.BEGIN)
1917                    return_ = self._match_text_seq("RETURN")
1918
1919                    if self._match(TokenType.STRING, advance=False):
1920                        # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
1921                        # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
1922                        expression = self._parse_string()
1923                        extend_props(self._parse_properties())
1924                    else:
1925                        expression = self._parse_user_defined_function_expression()
1926
1927                    end = self._match_text_seq("END")
1928
1929                    if return_:
1930                        expression = self.expression(exp.Return, this=expression)
1931        elif create_token.token_type == TokenType.INDEX:
1932            # Postgres allows anonymous indexes, eg. CREATE INDEX IF NOT EXISTS ON t(c)
1933            if not self._match(TokenType.ON):
1934                index = self._parse_id_var()
1935                anonymous = False
1936            else:
1937                index = None
1938                anonymous = True
1939
1940            this = self._parse_index(index=index, anonymous=anonymous)
1941        elif create_token.token_type in self.DB_CREATABLES:
1942            table_parts = self._parse_table_parts(
1943                schema=True, is_db_reference=create_token.token_type == TokenType.SCHEMA
1944            )
1945
1946            # exp.Properties.Location.POST_NAME
1947            self._match(TokenType.COMMA)
1948            extend_props(self._parse_properties(before=True))
1949
1950            this = self._parse_schema(this=table_parts)
1951
1952            # exp.Properties.Location.POST_SCHEMA and POST_WITH
1953            extend_props(self._parse_properties())
1954
1955            self._match(TokenType.ALIAS)
1956            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
1957                # exp.Properties.Location.POST_ALIAS
1958                extend_props(self._parse_properties())
1959
1960            if create_token.token_type == TokenType.SEQUENCE:
1961                expression = self._parse_types()
1962                extend_props(self._parse_properties())
1963            else:
1964                expression = self._parse_ddl_select()
1965
1966            if create_token.token_type == TokenType.TABLE:
1967                # exp.Properties.Location.POST_EXPRESSION
1968                extend_props(self._parse_properties())
1969
1970                indexes = []
1971                while True:
1972                    index = self._parse_index()
1973
1974                    # exp.Properties.Location.POST_INDEX
1975                    extend_props(self._parse_properties())
1976                    if not index:
1977                        break
1978                    else:
1979                        self._match(TokenType.COMMA)
1980                        indexes.append(index)
1981            elif create_token.token_type == TokenType.VIEW:
1982                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
1983                    no_schema_binding = True
1984            elif create_token.token_type in (TokenType.SINK, TokenType.SOURCE):
1985                extend_props(self._parse_properties())
1986
1987            shallow = self._match_text_seq("SHALLOW")
1988
1989            if self._match_texts(self.CLONE_KEYWORDS):
1990                copy = self._prev.text.lower() == "copy"
1991                clone = self.expression(
1992                    exp.Clone, this=self._parse_table(schema=True), shallow=shallow, copy=copy
1993                )
1994
1995        if self._curr and not self._match_set((TokenType.R_PAREN, TokenType.COMMA), advance=False):
1996            return self._parse_as_command(start)
1997
1998        create_kind_text = create_token.text.upper()
1999        return self.expression(
2000            exp.Create,
2001            this=this,
2002            kind=self.dialect.CREATABLE_KIND_MAPPING.get(create_kind_text) or create_kind_text,
2003            replace=replace,
2004            refresh=refresh,
2005            unique=unique,
2006            expression=expression,
2007            exists=exists,
2008            properties=properties,
2009            indexes=indexes,
2010            no_schema_binding=no_schema_binding,
2011            begin=begin,
2012            end=end,
2013            clone=clone,
2014            concurrently=concurrently,
2015            clustered=clustered,
2016        )
2017
2018    def _parse_sequence_properties(self) -> t.Optional[exp.SequenceProperties]:
2019        seq = exp.SequenceProperties()
2020
2021        options = []
2022        index = self._index
2023
2024        while self._curr:
2025            self._match(TokenType.COMMA)
2026            if self._match_text_seq("INCREMENT"):
2027                self._match_text_seq("BY")
2028                self._match_text_seq("=")
2029                seq.set("increment", self._parse_term())
2030            elif self._match_text_seq("MINVALUE"):
2031                seq.set("minvalue", self._parse_term())
2032            elif self._match_text_seq("MAXVALUE"):
2033                seq.set("maxvalue", self._parse_term())
2034            elif self._match(TokenType.START_WITH) or self._match_text_seq("START"):
2035                self._match_text_seq("=")
2036                seq.set("start", self._parse_term())
2037            elif self._match_text_seq("CACHE"):
2038                # T-SQL allows empty CACHE which is initialized dynamically
2039                seq.set("cache", self._parse_number() or True)
2040            elif self._match_text_seq("OWNED", "BY"):
2041                # "OWNED BY NONE" is the default
2042                seq.set("owned", None if self._match_text_seq("NONE") else self._parse_column())
2043            else:
2044                opt = self._parse_var_from_options(self.CREATE_SEQUENCE, raise_unmatched=False)
2045                if opt:
2046                    options.append(opt)
2047                else:
2048                    break
2049
2050        seq.set("options", options if options else None)
2051        return None if self._index == index else seq
2052
2053    def _parse_property_before(self) -> t.Optional[exp.Expression]:
2054        # only used for teradata currently
2055        self._match(TokenType.COMMA)
2056
2057        kwargs = {
2058            "no": self._match_text_seq("NO"),
2059            "dual": self._match_text_seq("DUAL"),
2060            "before": self._match_text_seq("BEFORE"),
2061            "default": self._match_text_seq("DEFAULT"),
2062            "local": (self._match_text_seq("LOCAL") and "LOCAL")
2063            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
2064            "after": self._match_text_seq("AFTER"),
2065            "minimum": self._match_texts(("MIN", "MINIMUM")),
2066            "maximum": self._match_texts(("MAX", "MAXIMUM")),
2067        }
2068
2069        if self._match_texts(self.PROPERTY_PARSERS):
2070            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
2071            try:
2072                return parser(self, **{k: v for k, v in kwargs.items() if v})
2073            except TypeError:
2074                self.raise_error(f"Cannot parse property '{self._prev.text}'")
2075
2076        return None
2077
2078    def _parse_wrapped_properties(self) -> t.List[exp.Expression]:
2079        return self._parse_wrapped_csv(self._parse_property)
2080
2081    def _parse_property(self) -> t.Optional[exp.Expression]:
2082        if self._match_texts(self.PROPERTY_PARSERS):
2083            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
2084
2085        if self._match(TokenType.DEFAULT) and self._match_texts(self.PROPERTY_PARSERS):
2086            return self.PROPERTY_PARSERS[self._prev.text.upper()](self, default=True)
2087
2088        if self._match_text_seq("COMPOUND", "SORTKEY"):
2089            return self._parse_sortkey(compound=True)
2090
2091        if self._match_text_seq("SQL", "SECURITY"):
2092            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
2093
2094        index = self._index
2095        key = self._parse_column()
2096
2097        if not self._match(TokenType.EQ):
2098            self._retreat(index)
2099            return self._parse_sequence_properties()
2100
2101        # Transform the key to exp.Dot if it's dotted identifiers wrapped in exp.Column or to exp.Var otherwise
2102        if isinstance(key, exp.Column):
2103            key = key.to_dot() if len(key.parts) > 1 else exp.var(key.name)
2104
2105        value = self._parse_bitwise() or self._parse_var(any_token=True)
2106
2107        # Transform the value to exp.Var if it was parsed as exp.Column(exp.Identifier())
2108        if isinstance(value, exp.Column):
2109            value = exp.var(value.name)
2110
2111        return self.expression(exp.Property, this=key, value=value)
2112
2113    def _parse_stored(self) -> exp.FileFormatProperty:
2114        self._match(TokenType.ALIAS)
2115
2116        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
2117        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
2118
2119        return self.expression(
2120            exp.FileFormatProperty,
2121            this=(
2122                self.expression(
2123                    exp.InputOutputFormat, input_format=input_format, output_format=output_format
2124                )
2125                if input_format or output_format
2126                else self._parse_var_or_string() or self._parse_number() or self._parse_id_var()
2127            ),
2128        )
2129
2130    def _parse_unquoted_field(self) -> t.Optional[exp.Expression]:
2131        field = self._parse_field()
2132        if isinstance(field, exp.Identifier) and not field.quoted:
2133            field = exp.var(field)
2134
2135        return field
2136
2137    def _parse_property_assignment(self, exp_class: t.Type[E], **kwargs: t.Any) -> E:
2138        self._match(TokenType.EQ)
2139        self._match(TokenType.ALIAS)
2140
2141        return self.expression(exp_class, this=self._parse_unquoted_field(), **kwargs)
2142
2143    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
2144        properties = []
2145        while True:
2146            if before:
2147                prop = self._parse_property_before()
2148            else:
2149                prop = self._parse_property()
2150            if not prop:
2151                break
2152            for p in ensure_list(prop):
2153                properties.append(p)
2154
2155        if properties:
2156            return self.expression(exp.Properties, expressions=properties)
2157
2158        return None
2159
2160    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
2161        return self.expression(
2162            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
2163        )
2164
2165    def _parse_security(self) -> t.Optional[exp.SecurityProperty]:
2166        if self._match_texts(("DEFINER", "INVOKER")):
2167            security_specifier = self._prev.text.upper()
2168            return self.expression(exp.SecurityProperty, this=security_specifier)
2169        return None
2170
2171    def _parse_settings_property(self) -> exp.SettingsProperty:
2172        return self.expression(
2173            exp.SettingsProperty, expressions=self._parse_csv(self._parse_assignment)
2174        )
2175
2176    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
2177        if self._index >= 2:
2178            pre_volatile_token = self._tokens[self._index - 2]
2179        else:
2180            pre_volatile_token = None
2181
2182        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
2183            return exp.VolatileProperty()
2184
2185        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
2186
2187    def _parse_retention_period(self) -> exp.Var:
2188        # Parse TSQL's HISTORY_RETENTION_PERIOD: {INFINITE | <number> DAY | DAYS | MONTH ...}
2189        number = self._parse_number()
2190        number_str = f"{number} " if number else ""
2191        unit = self._parse_var(any_token=True)
2192        return exp.var(f"{number_str}{unit}")
2193
2194    def _parse_system_versioning_property(
2195        self, with_: bool = False
2196    ) -> exp.WithSystemVersioningProperty:
2197        self._match(TokenType.EQ)
2198        prop = self.expression(
2199            exp.WithSystemVersioningProperty,
2200            **{  # type: ignore
2201                "on": True,
2202                "with": with_,
2203            },
2204        )
2205
2206        if self._match_text_seq("OFF"):
2207            prop.set("on", False)
2208            return prop
2209
2210        self._match(TokenType.ON)
2211        if self._match(TokenType.L_PAREN):
2212            while self._curr and not self._match(TokenType.R_PAREN):
2213                if self._match_text_seq("HISTORY_TABLE", "="):
2214                    prop.set("this", self._parse_table_parts())
2215                elif self._match_text_seq("DATA_CONSISTENCY_CHECK", "="):
2216                    prop.set("data_consistency", self._advance_any() and self._prev.text.upper())
2217                elif self._match_text_seq("HISTORY_RETENTION_PERIOD", "="):
2218                    prop.set("retention_period", self._parse_retention_period())
2219
2220                self._match(TokenType.COMMA)
2221
2222        return prop
2223
2224    def _parse_data_deletion_property(self) -> exp.DataDeletionProperty:
2225        self._match(TokenType.EQ)
2226        on = self._match_text_seq("ON") or not self._match_text_seq("OFF")
2227        prop = self.expression(exp.DataDeletionProperty, on=on)
2228
2229        if self._match(TokenType.L_PAREN):
2230            while self._curr and not self._match(TokenType.R_PAREN):
2231                if self._match_text_seq("FILTER_COLUMN", "="):
2232                    prop.set("filter_column", self._parse_column())
2233                elif self._match_text_seq("RETENTION_PERIOD", "="):
2234                    prop.set("retention_period", self._parse_retention_period())
2235
2236                self._match(TokenType.COMMA)
2237
2238        return prop
2239
2240    def _parse_distributed_property(self) -> exp.DistributedByProperty:
2241        kind = "HASH"
2242        expressions: t.Optional[t.List[exp.Expression]] = None
2243        if self._match_text_seq("BY", "HASH"):
2244            expressions = self._parse_wrapped_csv(self._parse_id_var)
2245        elif self._match_text_seq("BY", "RANDOM"):
2246            kind = "RANDOM"
2247
2248        # If the BUCKETS keyword is not present, the number of buckets is AUTO
2249        buckets: t.Optional[exp.Expression] = None
2250        if self._match_text_seq("BUCKETS") and not self._match_text_seq("AUTO"):
2251            buckets = self._parse_number()
2252
2253        return self.expression(
2254            exp.DistributedByProperty,
2255            expressions=expressions,
2256            kind=kind,
2257            buckets=buckets,
2258            order=self._parse_order(),
2259        )
2260
2261    def _parse_composite_key_property(self, expr_type: t.Type[E]) -> E:
2262        self._match_text_seq("KEY")
2263        expressions = self._parse_wrapped_id_vars()
2264        return self.expression(expr_type, expressions=expressions)
2265
2266    def _parse_with_property(self) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
2267        if self._match_text_seq("(", "SYSTEM_VERSIONING"):
2268            prop = self._parse_system_versioning_property(with_=True)
2269            self._match_r_paren()
2270            return prop
2271
2272        if self._match(TokenType.L_PAREN, advance=False):
2273            return self._parse_wrapped_properties()
2274
2275        if self._match_text_seq("JOURNAL"):
2276            return self._parse_withjournaltable()
2277
2278        if self._match_texts(self.VIEW_ATTRIBUTES):
2279            return self.expression(exp.ViewAttributeProperty, this=self._prev.text.upper())
2280
2281        if self._match_text_seq("DATA"):
2282            return self._parse_withdata(no=False)
2283        elif self._match_text_seq("NO", "DATA"):
2284            return self._parse_withdata(no=True)
2285
2286        if self._match(TokenType.SERDE_PROPERTIES, advance=False):
2287            return self._parse_serde_properties(with_=True)
2288
2289        if self._match(TokenType.SCHEMA):
2290            return self.expression(
2291                exp.WithSchemaBindingProperty,
2292                this=self._parse_var_from_options(self.SCHEMA_BINDING_OPTIONS),
2293            )
2294
2295        if self._match_texts(self.PROCEDURE_OPTIONS, advance=False):
2296            return self.expression(
2297                exp.WithProcedureOptions, expressions=self._parse_csv(self._parse_procedure_option)
2298            )
2299
2300        if not self._next:
2301            return None
2302
2303        return self._parse_withisolatedloading()
2304
2305    def _parse_procedure_option(self) -> exp.Expression | None:
2306        if self._match_text_seq("EXECUTE", "AS"):
2307            return self.expression(
2308                exp.ExecuteAsProperty,
2309                this=self._parse_var_from_options(self.EXECUTE_AS_OPTIONS, raise_unmatched=False)
2310                or self._parse_string(),
2311            )
2312
2313        return self._parse_var_from_options(self.PROCEDURE_OPTIONS)
2314
2315    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
2316    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
2317        self._match(TokenType.EQ)
2318
2319        user = self._parse_id_var()
2320        self._match(TokenType.PARAMETER)
2321        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
2322
2323        if not user or not host:
2324            return None
2325
2326        return exp.DefinerProperty(this=f"{user}@{host}")
2327
2328    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
2329        self._match(TokenType.TABLE)
2330        self._match(TokenType.EQ)
2331        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
2332
2333    def _parse_log(self, no: bool = False) -> exp.LogProperty:
2334        return self.expression(exp.LogProperty, no=no)
2335
2336    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
2337        return self.expression(exp.JournalProperty, **kwargs)
2338
2339    def _parse_checksum(self) -> exp.ChecksumProperty:
2340        self._match(TokenType.EQ)
2341
2342        on = None
2343        if self._match(TokenType.ON):
2344            on = True
2345        elif self._match_text_seq("OFF"):
2346            on = False
2347
2348        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
2349
2350    def _parse_cluster(self, wrapped: bool = False) -> exp.Cluster:
2351        return self.expression(
2352            exp.Cluster,
2353            expressions=(
2354                self._parse_wrapped_csv(self._parse_ordered)
2355                if wrapped
2356                else self._parse_csv(self._parse_ordered)
2357            ),
2358        )
2359
2360    def _parse_clustered_by(self) -> exp.ClusteredByProperty:
2361        self._match_text_seq("BY")
2362
2363        self._match_l_paren()
2364        expressions = self._parse_csv(self._parse_column)
2365        self._match_r_paren()
2366
2367        if self._match_text_seq("SORTED", "BY"):
2368            self._match_l_paren()
2369            sorted_by = self._parse_csv(self._parse_ordered)
2370            self._match_r_paren()
2371        else:
2372            sorted_by = None
2373
2374        self._match(TokenType.INTO)
2375        buckets = self._parse_number()
2376        self._match_text_seq("BUCKETS")
2377
2378        return self.expression(
2379            exp.ClusteredByProperty,
2380            expressions=expressions,
2381            sorted_by=sorted_by,
2382            buckets=buckets,
2383        )
2384
2385    def _parse_copy_property(self) -> t.Optional[exp.CopyGrantsProperty]:
2386        if not self._match_text_seq("GRANTS"):
2387            self._retreat(self._index - 1)
2388            return None
2389
2390        return self.expression(exp.CopyGrantsProperty)
2391
2392    def _parse_freespace(self) -> exp.FreespaceProperty:
2393        self._match(TokenType.EQ)
2394        return self.expression(
2395            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
2396        )
2397
2398    def _parse_mergeblockratio(
2399        self, no: bool = False, default: bool = False
2400    ) -> exp.MergeBlockRatioProperty:
2401        if self._match(TokenType.EQ):
2402            return self.expression(
2403                exp.MergeBlockRatioProperty,
2404                this=self._parse_number(),
2405                percent=self._match(TokenType.PERCENT),
2406            )
2407
2408        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
2409
2410    def _parse_datablocksize(
2411        self,
2412        default: t.Optional[bool] = None,
2413        minimum: t.Optional[bool] = None,
2414        maximum: t.Optional[bool] = None,
2415    ) -> exp.DataBlocksizeProperty:
2416        self._match(TokenType.EQ)
2417        size = self._parse_number()
2418
2419        units = None
2420        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
2421            units = self._prev.text
2422
2423        return self.expression(
2424            exp.DataBlocksizeProperty,
2425            size=size,
2426            units=units,
2427            default=default,
2428            minimum=minimum,
2429            maximum=maximum,
2430        )
2431
2432    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
2433        self._match(TokenType.EQ)
2434        always = self._match_text_seq("ALWAYS")
2435        manual = self._match_text_seq("MANUAL")
2436        never = self._match_text_seq("NEVER")
2437        default = self._match_text_seq("DEFAULT")
2438
2439        autotemp = None
2440        if self._match_text_seq("AUTOTEMP"):
2441            autotemp = self._parse_schema()
2442
2443        return self.expression(
2444            exp.BlockCompressionProperty,
2445            always=always,
2446            manual=manual,
2447            never=never,
2448            default=default,
2449            autotemp=autotemp,
2450        )
2451
2452    def _parse_withisolatedloading(self) -> t.Optional[exp.IsolatedLoadingProperty]:
2453        index = self._index
2454        no = self._match_text_seq("NO")
2455        concurrent = self._match_text_seq("CONCURRENT")
2456
2457        if not self._match_text_seq("ISOLATED", "LOADING"):
2458            self._retreat(index)
2459            return None
2460
2461        target = self._parse_var_from_options(self.ISOLATED_LOADING_OPTIONS, raise_unmatched=False)
2462        return self.expression(
2463            exp.IsolatedLoadingProperty, no=no, concurrent=concurrent, target=target
2464        )
2465
2466    def _parse_locking(self) -> exp.LockingProperty:
2467        if self._match(TokenType.TABLE):
2468            kind = "TABLE"
2469        elif self._match(TokenType.VIEW):
2470            kind = "VIEW"
2471        elif self._match(TokenType.ROW):
2472            kind = "ROW"
2473        elif self._match_text_seq("DATABASE"):
2474            kind = "DATABASE"
2475        else:
2476            kind = None
2477
2478        if kind in ("DATABASE", "TABLE", "VIEW"):
2479            this = self._parse_table_parts()
2480        else:
2481            this = None
2482
2483        if self._match(TokenType.FOR):
2484            for_or_in = "FOR"
2485        elif self._match(TokenType.IN):
2486            for_or_in = "IN"
2487        else:
2488            for_or_in = None
2489
2490        if self._match_text_seq("ACCESS"):
2491            lock_type = "ACCESS"
2492        elif self._match_texts(("EXCL", "EXCLUSIVE")):
2493            lock_type = "EXCLUSIVE"
2494        elif self._match_text_seq("SHARE"):
2495            lock_type = "SHARE"
2496        elif self._match_text_seq("READ"):
2497            lock_type = "READ"
2498        elif self._match_text_seq("WRITE"):
2499            lock_type = "WRITE"
2500        elif self._match_text_seq("CHECKSUM"):
2501            lock_type = "CHECKSUM"
2502        else:
2503            lock_type = None
2504
2505        override = self._match_text_seq("OVERRIDE")
2506
2507        return self.expression(
2508            exp.LockingProperty,
2509            this=this,
2510            kind=kind,
2511            for_or_in=for_or_in,
2512            lock_type=lock_type,
2513            override=override,
2514        )
2515
2516    def _parse_partition_by(self) -> t.List[exp.Expression]:
2517        if self._match(TokenType.PARTITION_BY):
2518            return self._parse_csv(self._parse_assignment)
2519        return []
2520
2521    def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
2522        def _parse_partition_bound_expr() -> t.Optional[exp.Expression]:
2523            if self._match_text_seq("MINVALUE"):
2524                return exp.var("MINVALUE")
2525            if self._match_text_seq("MAXVALUE"):
2526                return exp.var("MAXVALUE")
2527            return self._parse_bitwise()
2528
2529        this: t.Optional[exp.Expression | t.List[exp.Expression]] = None
2530        expression = None
2531        from_expressions = None
2532        to_expressions = None
2533
2534        if self._match(TokenType.IN):
2535            this = self._parse_wrapped_csv(self._parse_bitwise)
2536        elif self._match(TokenType.FROM):
2537            from_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
2538            self._match_text_seq("TO")
2539            to_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
2540        elif self._match_text_seq("WITH", "(", "MODULUS"):
2541            this = self._parse_number()
2542            self._match_text_seq(",", "REMAINDER")
2543            expression = self._parse_number()
2544            self._match_r_paren()
2545        else:
2546            self.raise_error("Failed to parse partition bound spec.")
2547
2548        return self.expression(
2549            exp.PartitionBoundSpec,
2550            this=this,
2551            expression=expression,
2552            from_expressions=from_expressions,
2553            to_expressions=to_expressions,
2554        )
2555
2556    # https://www.postgresql.org/docs/current/sql-createtable.html
2557    def _parse_partitioned_of(self) -> t.Optional[exp.PartitionedOfProperty]:
2558        if not self._match_text_seq("OF"):
2559            self._retreat(self._index - 1)
2560            return None
2561
2562        this = self._parse_table(schema=True)
2563
2564        if self._match(TokenType.DEFAULT):
2565            expression: exp.Var | exp.PartitionBoundSpec = exp.var("DEFAULT")
2566        elif self._match_text_seq("FOR", "VALUES"):
2567            expression = self._parse_partition_bound_spec()
2568        else:
2569            self.raise_error("Expecting either DEFAULT or FOR VALUES clause.")
2570
2571        return self.expression(exp.PartitionedOfProperty, this=this, expression=expression)
2572
2573    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
2574        self._match(TokenType.EQ)
2575        return self.expression(
2576            exp.PartitionedByProperty,
2577            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
2578        )
2579
2580    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
2581        if self._match_text_seq("AND", "STATISTICS"):
2582            statistics = True
2583        elif self._match_text_seq("AND", "NO", "STATISTICS"):
2584            statistics = False
2585        else:
2586            statistics = None
2587
2588        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
2589
2590    def _parse_contains_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2591        if self._match_text_seq("SQL"):
2592            return self.expression(exp.SqlReadWriteProperty, this="CONTAINS SQL")
2593        return None
2594
2595    def _parse_modifies_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2596        if self._match_text_seq("SQL", "DATA"):
2597            return self.expression(exp.SqlReadWriteProperty, this="MODIFIES SQL DATA")
2598        return None
2599
2600    def _parse_no_property(self) -> t.Optional[exp.Expression]:
2601        if self._match_text_seq("PRIMARY", "INDEX"):
2602            return exp.NoPrimaryIndexProperty()
2603        if self._match_text_seq("SQL"):
2604            return self.expression(exp.SqlReadWriteProperty, this="NO SQL")
2605        return None
2606
2607    def _parse_on_property(self) -> t.Optional[exp.Expression]:
2608        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
2609            return exp.OnCommitProperty()
2610        if self._match_text_seq("COMMIT", "DELETE", "ROWS"):
2611            return exp.OnCommitProperty(delete=True)
2612        return self.expression(exp.OnProperty, this=self._parse_schema(self._parse_id_var()))
2613
2614    def _parse_reads_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2615        if self._match_text_seq("SQL", "DATA"):
2616            return self.expression(exp.SqlReadWriteProperty, this="READS SQL DATA")
2617        return None
2618
2619    def _parse_distkey(self) -> exp.DistKeyProperty:
2620        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
2621
2622    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
2623        table = self._parse_table(schema=True)
2624
2625        options = []
2626        while self._match_texts(("INCLUDING", "EXCLUDING")):
2627            this = self._prev.text.upper()
2628
2629            id_var = self._parse_id_var()
2630            if not id_var:
2631                return None
2632
2633            options.append(
2634                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
2635            )
2636
2637        return self.expression(exp.LikeProperty, this=table, expressions=options)
2638
2639    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
2640        return self.expression(
2641            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
2642        )
2643
2644    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
2645        self._match(TokenType.EQ)
2646        return self.expression(
2647            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
2648        )
2649
2650    def _parse_remote_with_connection(self) -> exp.RemoteWithConnectionModelProperty:
2651        self._match_text_seq("WITH", "CONNECTION")
2652        return self.expression(
2653            exp.RemoteWithConnectionModelProperty, this=self._parse_table_parts()
2654        )
2655
2656    def _parse_returns(self) -> exp.ReturnsProperty:
2657        value: t.Optional[exp.Expression]
2658        null = None
2659        is_table = self._match(TokenType.TABLE)
2660
2661        if is_table:
2662            if self._match(TokenType.LT):
2663                value = self.expression(
2664                    exp.Schema,
2665                    this="TABLE",
2666                    expressions=self._parse_csv(self._parse_struct_types),
2667                )
2668                if not self._match(TokenType.GT):
2669                    self.raise_error("Expecting >")
2670            else:
2671                value = self._parse_schema(exp.var("TABLE"))
2672        elif self._match_text_seq("NULL", "ON", "NULL", "INPUT"):
2673            null = True
2674            value = None
2675        else:
2676            value = self._parse_types()
2677
2678        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table, null=null)
2679
2680    def _parse_describe(self) -> exp.Describe:
2681        kind = self._match_set(self.CREATABLES) and self._prev.text
2682        style = self._match_texts(self.DESCRIBE_STYLES) and self._prev.text.upper()
2683        if self._match(TokenType.DOT):
2684            style = None
2685            self._retreat(self._index - 2)
2686
2687        format = self._parse_property() if self._match(TokenType.FORMAT, advance=False) else None
2688
2689        if self._match_set(self.STATEMENT_PARSERS, advance=False):
2690            this = self._parse_statement()
2691        else:
2692            this = self._parse_table(schema=True)
2693
2694        properties = self._parse_properties()
2695        expressions = properties.expressions if properties else None
2696        partition = self._parse_partition()
2697        return self.expression(
2698            exp.Describe,
2699            this=this,
2700            style=style,
2701            kind=kind,
2702            expressions=expressions,
2703            partition=partition,
2704            format=format,
2705        )
2706
2707    def _parse_multitable_inserts(self, comments: t.Optional[t.List[str]]) -> exp.MultitableInserts:
2708        kind = self._prev.text.upper()
2709        expressions = []
2710
2711        def parse_conditional_insert() -> t.Optional[exp.ConditionalInsert]:
2712            if self._match(TokenType.WHEN):
2713                expression = self._parse_disjunction()
2714                self._match(TokenType.THEN)
2715            else:
2716                expression = None
2717
2718            else_ = self._match(TokenType.ELSE)
2719
2720            if not self._match(TokenType.INTO):
2721                return None
2722
2723            return self.expression(
2724                exp.ConditionalInsert,
2725                this=self.expression(
2726                    exp.Insert,
2727                    this=self._parse_table(schema=True),
2728                    expression=self._parse_derived_table_values(),
2729                ),
2730                expression=expression,
2731                else_=else_,
2732            )
2733
2734        expression = parse_conditional_insert()
2735        while expression is not None:
2736            expressions.append(expression)
2737            expression = parse_conditional_insert()
2738
2739        return self.expression(
2740            exp.MultitableInserts,
2741            kind=kind,
2742            comments=comments,
2743            expressions=expressions,
2744            source=self._parse_table(),
2745        )
2746
2747    def _parse_insert(self) -> t.Union[exp.Insert, exp.MultitableInserts]:
2748        comments = []
2749        hint = self._parse_hint()
2750        overwrite = self._match(TokenType.OVERWRITE)
2751        ignore = self._match(TokenType.IGNORE)
2752        local = self._match_text_seq("LOCAL")
2753        alternative = None
2754        is_function = None
2755
2756        if self._match_text_seq("DIRECTORY"):
2757            this: t.Optional[exp.Expression] = self.expression(
2758                exp.Directory,
2759                this=self._parse_var_or_string(),
2760                local=local,
2761                row_format=self._parse_row_format(match_row=True),
2762            )
2763        else:
2764            if self._match_set((TokenType.FIRST, TokenType.ALL)):
2765                comments += ensure_list(self._prev_comments)
2766                return self._parse_multitable_inserts(comments)
2767
2768            if self._match(TokenType.OR):
2769                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
2770
2771            self._match(TokenType.INTO)
2772            comments += ensure_list(self._prev_comments)
2773            self._match(TokenType.TABLE)
2774            is_function = self._match(TokenType.FUNCTION)
2775
2776            this = (
2777                self._parse_table(schema=True, parse_partition=True)
2778                if not is_function
2779                else self._parse_function()
2780            )
2781            if isinstance(this, exp.Table) and self._match(TokenType.ALIAS, advance=False):
2782                this.set("alias", self._parse_table_alias())
2783
2784        returning = self._parse_returning()
2785
2786        return self.expression(
2787            exp.Insert,
2788            comments=comments,
2789            hint=hint,
2790            is_function=is_function,
2791            this=this,
2792            stored=self._match_text_seq("STORED") and self._parse_stored(),
2793            by_name=self._match_text_seq("BY", "NAME"),
2794            exists=self._parse_exists(),
2795            where=self._match_pair(TokenType.REPLACE, TokenType.WHERE) and self._parse_assignment(),
2796            partition=self._match(TokenType.PARTITION_BY) and self._parse_partitioned_by(),
2797            settings=self._match_text_seq("SETTINGS") and self._parse_settings_property(),
2798            expression=self._parse_derived_table_values() or self._parse_ddl_select(),
2799            conflict=self._parse_on_conflict(),
2800            returning=returning or self._parse_returning(),
2801            overwrite=overwrite,
2802            alternative=alternative,
2803            ignore=ignore,
2804            source=self._match(TokenType.TABLE) and self._parse_table(),
2805        )
2806
2807    def _parse_kill(self) -> exp.Kill:
2808        kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
2809
2810        return self.expression(
2811            exp.Kill,
2812            this=self._parse_primary(),
2813            kind=kind,
2814        )
2815
2816    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
2817        conflict = self._match_text_seq("ON", "CONFLICT")
2818        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
2819
2820        if not conflict and not duplicate:
2821            return None
2822
2823        conflict_keys = None
2824        constraint = None
2825
2826        if conflict:
2827            if self._match_text_seq("ON", "CONSTRAINT"):
2828                constraint = self._parse_id_var()
2829            elif self._match(TokenType.L_PAREN):
2830                conflict_keys = self._parse_csv(self._parse_id_var)
2831                self._match_r_paren()
2832
2833        action = self._parse_var_from_options(self.CONFLICT_ACTIONS)
2834        if self._prev.token_type == TokenType.UPDATE:
2835            self._match(TokenType.SET)
2836            expressions = self._parse_csv(self._parse_equality)
2837        else:
2838            expressions = None
2839
2840        return self.expression(
2841            exp.OnConflict,
2842            duplicate=duplicate,
2843            expressions=expressions,
2844            action=action,
2845            conflict_keys=conflict_keys,
2846            constraint=constraint,
2847            where=self._parse_where(),
2848        )
2849
2850    def _parse_returning(self) -> t.Optional[exp.Returning]:
2851        if not self._match(TokenType.RETURNING):
2852            return None
2853        return self.expression(
2854            exp.Returning,
2855            expressions=self._parse_csv(self._parse_expression),
2856            into=self._match(TokenType.INTO) and self._parse_table_part(),
2857        )
2858
2859    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2860        if not self._match(TokenType.FORMAT):
2861            return None
2862        return self._parse_row_format()
2863
2864    def _parse_serde_properties(self, with_: bool = False) -> t.Optional[exp.SerdeProperties]:
2865        index = self._index
2866        with_ = with_ or self._match_text_seq("WITH")
2867
2868        if not self._match(TokenType.SERDE_PROPERTIES):
2869            self._retreat(index)
2870            return None
2871        return self.expression(
2872            exp.SerdeProperties,
2873            **{  # type: ignore
2874                "expressions": self._parse_wrapped_properties(),
2875                "with": with_,
2876            },
2877        )
2878
2879    def _parse_row_format(
2880        self, match_row: bool = False
2881    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2882        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
2883            return None
2884
2885        if self._match_text_seq("SERDE"):
2886            this = self._parse_string()
2887
2888            serde_properties = self._parse_serde_properties()
2889
2890            return self.expression(
2891                exp.RowFormatSerdeProperty, this=this, serde_properties=serde_properties
2892            )
2893
2894        self._match_text_seq("DELIMITED")
2895
2896        kwargs = {}
2897
2898        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
2899            kwargs["fields"] = self._parse_string()
2900            if self._match_text_seq("ESCAPED", "BY"):
2901                kwargs["escaped"] = self._parse_string()
2902        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
2903            kwargs["collection_items"] = self._parse_string()
2904        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
2905            kwargs["map_keys"] = self._parse_string()
2906        if self._match_text_seq("LINES", "TERMINATED", "BY"):
2907            kwargs["lines"] = self._parse_string()
2908        if self._match_text_seq("NULL", "DEFINED", "AS"):
2909            kwargs["null"] = self._parse_string()
2910
2911        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
2912
2913    def _parse_load(self) -> exp.LoadData | exp.Command:
2914        if self._match_text_seq("DATA"):
2915            local = self._match_text_seq("LOCAL")
2916            self._match_text_seq("INPATH")
2917            inpath = self._parse_string()
2918            overwrite = self._match(TokenType.OVERWRITE)
2919            self._match_pair(TokenType.INTO, TokenType.TABLE)
2920
2921            return self.expression(
2922                exp.LoadData,
2923                this=self._parse_table(schema=True),
2924                local=local,
2925                overwrite=overwrite,
2926                inpath=inpath,
2927                partition=self._parse_partition(),
2928                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
2929                serde=self._match_text_seq("SERDE") and self._parse_string(),
2930            )
2931        return self._parse_as_command(self._prev)
2932
2933    def _parse_delete(self) -> exp.Delete:
2934        # This handles MySQL's "Multiple-Table Syntax"
2935        # https://dev.mysql.com/doc/refman/8.0/en/delete.html
2936        tables = None
2937        if not self._match(TokenType.FROM, advance=False):
2938            tables = self._parse_csv(self._parse_table) or None
2939
2940        returning = self._parse_returning()
2941
2942        return self.expression(
2943            exp.Delete,
2944            tables=tables,
2945            this=self._match(TokenType.FROM) and self._parse_table(joins=True),
2946            using=self._match(TokenType.USING) and self._parse_table(joins=True),
2947            cluster=self._match(TokenType.ON) and self._parse_on_property(),
2948            where=self._parse_where(),
2949            returning=returning or self._parse_returning(),
2950            limit=self._parse_limit(),
2951        )
2952
2953    def _parse_update(self) -> exp.Update:
2954        this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
2955        expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
2956        returning = self._parse_returning()
2957        return self.expression(
2958            exp.Update,
2959            **{  # type: ignore
2960                "this": this,
2961                "expressions": expressions,
2962                "from": self._parse_from(joins=True),
2963                "where": self._parse_where(),
2964                "returning": returning or self._parse_returning(),
2965                "order": self._parse_order(),
2966                "limit": self._parse_limit(),
2967            },
2968        )
2969
2970    def _parse_uncache(self) -> exp.Uncache:
2971        if not self._match(TokenType.TABLE):
2972            self.raise_error("Expecting TABLE after UNCACHE")
2973
2974        return self.expression(
2975            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
2976        )
2977
2978    def _parse_cache(self) -> exp.Cache:
2979        lazy = self._match_text_seq("LAZY")
2980        self._match(TokenType.TABLE)
2981        table = self._parse_table(schema=True)
2982
2983        options = []
2984        if self._match_text_seq("OPTIONS"):
2985            self._match_l_paren()
2986            k = self._parse_string()
2987            self._match(TokenType.EQ)
2988            v = self._parse_string()
2989            options = [k, v]
2990            self._match_r_paren()
2991
2992        self._match(TokenType.ALIAS)
2993        return self.expression(
2994            exp.Cache,
2995            this=table,
2996            lazy=lazy,
2997            options=options,
2998            expression=self._parse_select(nested=True),
2999        )
3000
3001    def _parse_partition(self) -> t.Optional[exp.Partition]:
3002        if not self._match_texts(self.PARTITION_KEYWORDS):
3003            return None
3004
3005        return self.expression(
3006            exp.Partition,
3007            subpartition=self._prev.text.upper() == "SUBPARTITION",
3008            expressions=self._parse_wrapped_csv(self._parse_assignment),
3009        )
3010
3011    def _parse_value(self) -> t.Optional[exp.Tuple]:
3012        def _parse_value_expression() -> t.Optional[exp.Expression]:
3013            if self.dialect.SUPPORTS_VALUES_DEFAULT and self._match(TokenType.DEFAULT):
3014                return exp.var(self._prev.text.upper())
3015            return self._parse_expression()
3016
3017        if self._match(TokenType.L_PAREN):
3018            expressions = self._parse_csv(_parse_value_expression)
3019            self._match_r_paren()
3020            return self.expression(exp.Tuple, expressions=expressions)
3021
3022        # In some dialects we can have VALUES 1, 2 which results in 1 column & 2 rows.
3023        expression = self._parse_expression()
3024        if expression:
3025            return self.expression(exp.Tuple, expressions=[expression])
3026        return None
3027
3028    def _parse_projections(self) -> t.List[exp.Expression]:
3029        return self._parse_expressions()
3030
3031    def _parse_select(
3032        self,
3033        nested: bool = False,
3034        table: bool = False,
3035        parse_subquery_alias: bool = True,
3036        parse_set_operation: bool = True,
3037    ) -> t.Optional[exp.Expression]:
3038        cte = self._parse_with()
3039
3040        if cte:
3041            this = self._parse_statement()
3042
3043            if not this:
3044                self.raise_error("Failed to parse any statement following CTE")
3045                return cte
3046
3047            if "with" in this.arg_types:
3048                this.set("with", cte)
3049            else:
3050                self.raise_error(f"{this.key} does not support CTE")
3051                this = cte
3052
3053            return this
3054
3055        # duckdb supports leading with FROM x
3056        from_ = self._parse_from() if self._match(TokenType.FROM, advance=False) else None
3057
3058        if self._match(TokenType.SELECT):
3059            comments = self._prev_comments
3060
3061            hint = self._parse_hint()
3062
3063            if self._next and not self._next.token_type == TokenType.DOT:
3064                all_ = self._match(TokenType.ALL)
3065                distinct = self._match_set(self.DISTINCT_TOKENS)
3066            else:
3067                all_, distinct = None, None
3068
3069            kind = (
3070                self._match(TokenType.ALIAS)
3071                and self._match_texts(("STRUCT", "VALUE"))
3072                and self._prev.text.upper()
3073            )
3074
3075            if distinct:
3076                distinct = self.expression(
3077                    exp.Distinct,
3078                    on=self._parse_value() if self._match(TokenType.ON) else None,
3079                )
3080
3081            if all_ and distinct:
3082                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
3083
3084            operation_modifiers = []
3085            while self._curr and self._match_texts(self.OPERATION_MODIFIERS):
3086                operation_modifiers.append(exp.var(self._prev.text.upper()))
3087
3088            limit = self._parse_limit(top=True)
3089            projections = self._parse_projections()
3090
3091            this = self.expression(
3092                exp.Select,
3093                kind=kind,
3094                hint=hint,
3095                distinct=distinct,
3096                expressions=projections,
3097                limit=limit,
3098                operation_modifiers=operation_modifiers or None,
3099            )
3100            this.comments = comments
3101
3102            into = self._parse_into()
3103            if into:
3104                this.set("into", into)
3105
3106            if not from_:
3107                from_ = self._parse_from()
3108
3109            if from_:
3110                this.set("from", from_)
3111
3112            this = self._parse_query_modifiers(this)
3113        elif (table or nested) and self._match(TokenType.L_PAREN):
3114            if self._match_set((TokenType.PIVOT, TokenType.UNPIVOT)):
3115                this = self._parse_simplified_pivot(
3116                    is_unpivot=self._prev.token_type == TokenType.UNPIVOT
3117                )
3118            elif self._match(TokenType.FROM):
3119                from_ = self._parse_from(skip_from_token=True)
3120                # Support parentheses for duckdb FROM-first syntax
3121                select = self._parse_select()
3122                if select:
3123                    select.set("from", from_)
3124                    this = select
3125                else:
3126                    this = exp.select("*").from_(t.cast(exp.From, from_))
3127            else:
3128                this = (
3129                    self._parse_table()
3130                    if table
3131                    else self._parse_select(nested=True, parse_set_operation=False)
3132                )
3133
3134                # Transform exp.Values into a exp.Table to pass through parse_query_modifiers
3135                # in case a modifier (e.g. join) is following
3136                if table and isinstance(this, exp.Values) and this.alias:
3137                    alias = this.args["alias"].pop()
3138                    this = exp.Table(this=this, alias=alias)
3139
3140                this = self._parse_query_modifiers(self._parse_set_operations(this))
3141
3142            self._match_r_paren()
3143
3144            # We return early here so that the UNION isn't attached to the subquery by the
3145            # following call to _parse_set_operations, but instead becomes the parent node
3146            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
3147        elif self._match(TokenType.VALUES, advance=False):
3148            this = self._parse_derived_table_values()
3149        elif from_:
3150            this = exp.select("*").from_(from_.this, copy=False)
3151        elif self._match(TokenType.SUMMARIZE):
3152            table = self._match(TokenType.TABLE)
3153            this = self._parse_select() or self._parse_string() or self._parse_table()
3154            return self.expression(exp.Summarize, this=this, table=table)
3155        elif self._match(TokenType.DESCRIBE):
3156            this = self._parse_describe()
3157        elif self._match_text_seq("STREAM"):
3158            this = self._parse_function()
3159            if this:
3160                this = self.expression(exp.Stream, this=this)
3161            else:
3162                self._retreat(self._index - 1)
3163        else:
3164            this = None
3165
3166        return self._parse_set_operations(this) if parse_set_operation else this
3167
3168    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
3169        if not skip_with_token and not self._match(TokenType.WITH):
3170            return None
3171
3172        comments = self._prev_comments
3173        recursive = self._match(TokenType.RECURSIVE)
3174
3175        last_comments = None
3176        expressions = []
3177        while True:
3178            expressions.append(self._parse_cte())
3179            if last_comments:
3180                expressions[-1].add_comments(last_comments)
3181
3182            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
3183                break
3184            else:
3185                self._match(TokenType.WITH)
3186
3187            last_comments = self._prev_comments
3188
3189        return self.expression(
3190            exp.With, comments=comments, expressions=expressions, recursive=recursive
3191        )
3192
3193    def _parse_cte(self) -> t.Optional[exp.CTE]:
3194        index = self._index
3195
3196        alias = self._parse_table_alias(self.ID_VAR_TOKENS)
3197        if not alias or not alias.this:
3198            self.raise_error("Expected CTE to have alias")
3199
3200        if not self._match(TokenType.ALIAS) and not self.OPTIONAL_ALIAS_TOKEN_CTE:
3201            self._retreat(index)
3202            return None
3203
3204        comments = self._prev_comments
3205
3206        if self._match_text_seq("NOT", "MATERIALIZED"):
3207            materialized = False
3208        elif self._match_text_seq("MATERIALIZED"):
3209            materialized = True
3210        else:
3211            materialized = None
3212
3213        cte = self.expression(
3214            exp.CTE,
3215            this=self._parse_wrapped(self._parse_statement),
3216            alias=alias,
3217            materialized=materialized,
3218            comments=comments,
3219        )
3220
3221        if isinstance(cte.this, exp.Values):
3222            cte.set("this", exp.select("*").from_(exp.alias_(cte.this, "_values", table=True)))
3223
3224        return cte
3225
3226    def _parse_table_alias(
3227        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
3228    ) -> t.Optional[exp.TableAlias]:
3229        # In some dialects, LIMIT and OFFSET can act as both identifiers and keywords (clauses)
3230        # so this section tries to parse the clause version and if it fails, it treats the token
3231        # as an identifier (alias)
3232        if self._can_parse_limit_or_offset():
3233            return None
3234
3235        any_token = self._match(TokenType.ALIAS)
3236        alias = (
3237            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
3238            or self._parse_string_as_identifier()
3239        )
3240
3241        index = self._index
3242        if self._match(TokenType.L_PAREN):
3243            columns = self._parse_csv(self._parse_function_parameter)
3244            self._match_r_paren() if columns else self._retreat(index)
3245        else:
3246            columns = None
3247
3248        if not alias and not columns:
3249            return None
3250
3251        table_alias = self.expression(exp.TableAlias, this=alias, columns=columns)
3252
3253        # We bubble up comments from the Identifier to the TableAlias
3254        if isinstance(alias, exp.Identifier):
3255            table_alias.add_comments(alias.pop_comments())
3256
3257        return table_alias
3258
3259    def _parse_subquery(
3260        self, this: t.Optional[exp.Expression], parse_alias: bool = True
3261    ) -> t.Optional[exp.Subquery]:
3262        if not this:
3263            return None
3264
3265        return self.expression(
3266            exp.Subquery,
3267            this=this,
3268            pivots=self._parse_pivots(),
3269            alias=self._parse_table_alias() if parse_alias else None,
3270            sample=self._parse_table_sample(),
3271        )
3272
3273    def _implicit_unnests_to_explicit(self, this: E) -> E:
3274        from sqlglot.optimizer.normalize_identifiers import normalize_identifiers as _norm
3275
3276        refs = {_norm(this.args["from"].this.copy(), dialect=self.dialect).alias_or_name}
3277        for i, join in enumerate(this.args.get("joins") or []):
3278            table = join.this
3279            normalized_table = table.copy()
3280            normalized_table.meta["maybe_column"] = True
3281            normalized_table = _norm(normalized_table, dialect=self.dialect)
3282
3283            if isinstance(table, exp.Table) and not join.args.get("on"):
3284                if normalized_table.parts[0].name in refs:
3285                    table_as_column = table.to_column()
3286                    unnest = exp.Unnest(expressions=[table_as_column])
3287
3288                    # Table.to_column creates a parent Alias node that we want to convert to
3289                    # a TableAlias and attach to the Unnest, so it matches the parser's output
3290                    if isinstance(table.args.get("alias"), exp.TableAlias):
3291                        table_as_column.replace(table_as_column.this)
3292                        exp.alias_(unnest, None, table=[table.args["alias"].this], copy=False)
3293
3294                    table.replace(unnest)
3295
3296            refs.add(normalized_table.alias_or_name)
3297
3298        return this
3299
3300    def _parse_query_modifiers(
3301        self, this: t.Optional[exp.Expression]
3302    ) -> t.Optional[exp.Expression]:
3303        if isinstance(this, (exp.Query, exp.Table)):
3304            for join in self._parse_joins():
3305                this.append("joins", join)
3306            for lateral in iter(self._parse_lateral, None):
3307                this.append("laterals", lateral)
3308
3309            while True:
3310                if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
3311                    parser = self.QUERY_MODIFIER_PARSERS[self._curr.token_type]
3312                    key, expression = parser(self)
3313
3314                    if expression:
3315                        this.set(key, expression)
3316                        if key == "limit":
3317                            offset = expression.args.pop("offset", None)
3318
3319                            if offset:
3320                                offset = exp.Offset(expression=offset)
3321                                this.set("offset", offset)
3322
3323                                limit_by_expressions = expression.expressions
3324                                expression.set("expressions", None)
3325                                offset.set("expressions", limit_by_expressions)
3326                        continue
3327                break
3328
3329        if self.SUPPORTS_IMPLICIT_UNNEST and this and this.args.get("from"):
3330            this = self._implicit_unnests_to_explicit(this)
3331
3332        return this
3333
3334    def _parse_hint_fallback_to_string(self) -> t.Optional[exp.Hint]:
3335        start = self._curr
3336        while self._curr:
3337            self._advance()
3338
3339        end = self._tokens[self._index - 1]
3340        return exp.Hint(expressions=[self._find_sql(start, end)])
3341
3342    def _parse_hint_function_call(self) -> t.Optional[exp.Expression]:
3343        return self._parse_function_call()
3344
3345    def _parse_hint_body(self) -> t.Optional[exp.Hint]:
3346        start_index = self._index
3347        should_fallback_to_string = False
3348
3349        hints = []
3350        try:
3351            for hint in iter(
3352                lambda: self._parse_csv(
3353                    lambda: self._parse_hint_function_call() or self._parse_var(upper=True),
3354                ),
3355                [],
3356            ):
3357                hints.extend(hint)
3358        except ParseError:
3359            should_fallback_to_string = True
3360
3361        if should_fallback_to_string or self._curr:
3362            self._retreat(start_index)
3363            return self._parse_hint_fallback_to_string()
3364
3365        return self.expression(exp.Hint, expressions=hints)
3366
3367    def _parse_hint(self) -> t.Optional[exp.Hint]:
3368        if self._match(TokenType.HINT) and self._prev_comments:
3369            return exp.maybe_parse(self._prev_comments[0], into=exp.Hint, dialect=self.dialect)
3370
3371        return None
3372
3373    def _parse_into(self) -> t.Optional[exp.Into]:
3374        if not self._match(TokenType.INTO):
3375            return None
3376
3377        temp = self._match(TokenType.TEMPORARY)
3378        unlogged = self._match_text_seq("UNLOGGED")
3379        self._match(TokenType.TABLE)
3380
3381        return self.expression(
3382            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
3383        )
3384
3385    def _parse_from(
3386        self, joins: bool = False, skip_from_token: bool = False
3387    ) -> t.Optional[exp.From]:
3388        if not skip_from_token and not self._match(TokenType.FROM):
3389            return None
3390
3391        return self.expression(
3392            exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
3393        )
3394
3395    def _parse_match_recognize_measure(self) -> exp.MatchRecognizeMeasure:
3396        return self.expression(
3397            exp.MatchRecognizeMeasure,
3398            window_frame=self._match_texts(("FINAL", "RUNNING")) and self._prev.text.upper(),
3399            this=self._parse_expression(),
3400        )
3401
3402    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
3403        if not self._match(TokenType.MATCH_RECOGNIZE):
3404            return None
3405
3406        self._match_l_paren()
3407
3408        partition = self._parse_partition_by()
3409        order = self._parse_order()
3410
3411        measures = (
3412            self._parse_csv(self._parse_match_recognize_measure)
3413            if self._match_text_seq("MEASURES")
3414            else None
3415        )
3416
3417        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
3418            rows = exp.var("ONE ROW PER MATCH")
3419        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
3420            text = "ALL ROWS PER MATCH"
3421            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
3422                text += " SHOW EMPTY MATCHES"
3423            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
3424                text += " OMIT EMPTY MATCHES"
3425            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
3426                text += " WITH UNMATCHED ROWS"
3427            rows = exp.var(text)
3428        else:
3429            rows = None
3430
3431        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
3432            text = "AFTER MATCH SKIP"
3433            if self._match_text_seq("PAST", "LAST", "ROW"):
3434                text += " PAST LAST ROW"
3435            elif self._match_text_seq("TO", "NEXT", "ROW"):
3436                text += " TO NEXT ROW"
3437            elif self._match_text_seq("TO", "FIRST"):
3438                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
3439            elif self._match_text_seq("TO", "LAST"):
3440                text += f" TO LAST {self._advance_any().text}"  # type: ignore
3441            after = exp.var(text)
3442        else:
3443            after = None
3444
3445        if self._match_text_seq("PATTERN"):
3446            self._match_l_paren()
3447
3448            if not self._curr:
3449                self.raise_error("Expecting )", self._curr)
3450
3451            paren = 1
3452            start = self._curr
3453
3454            while self._curr and paren > 0:
3455                if self._curr.token_type == TokenType.L_PAREN:
3456                    paren += 1
3457                if self._curr.token_type == TokenType.R_PAREN:
3458                    paren -= 1
3459
3460                end = self._prev
3461                self._advance()
3462
3463            if paren > 0:
3464                self.raise_error("Expecting )", self._curr)
3465
3466            pattern = exp.var(self._find_sql(start, end))
3467        else:
3468            pattern = None
3469
3470        define = (
3471            self._parse_csv(self._parse_name_as_expression)
3472            if self._match_text_seq("DEFINE")
3473            else None
3474        )
3475
3476        self._match_r_paren()
3477
3478        return self.expression(
3479            exp.MatchRecognize,
3480            partition_by=partition,
3481            order=order,
3482            measures=measures,
3483            rows=rows,
3484            after=after,
3485            pattern=pattern,
3486            define=define,
3487            alias=self._parse_table_alias(),
3488        )
3489
3490    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
3491        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
3492        if not cross_apply and self._match_pair(TokenType.OUTER, TokenType.APPLY):
3493            cross_apply = False
3494
3495        if cross_apply is not None:
3496            this = self._parse_select(table=True)
3497            view = None
3498            outer = None
3499        elif self._match(TokenType.LATERAL):
3500            this = self._parse_select(table=True)
3501            view = self._match(TokenType.VIEW)
3502            outer = self._match(TokenType.OUTER)
3503        else:
3504            return None
3505
3506        if not this:
3507            this = (
3508                self._parse_unnest()
3509                or self._parse_function()
3510                or self._parse_id_var(any_token=False)
3511            )
3512
3513            while self._match(TokenType.DOT):
3514                this = exp.Dot(
3515                    this=this,
3516                    expression=self._parse_function() or self._parse_id_var(any_token=False),
3517                )
3518
3519        if view:
3520            table = self._parse_id_var(any_token=False)
3521            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
3522            table_alias: t.Optional[exp.TableAlias] = self.expression(
3523                exp.TableAlias, this=table, columns=columns
3524            )
3525        elif isinstance(this, (exp.Subquery, exp.Unnest)) and this.alias:
3526            # We move the alias from the lateral's child node to the lateral itself
3527            table_alias = this.args["alias"].pop()
3528        else:
3529            table_alias = self._parse_table_alias()
3530
3531        return self.expression(
3532            exp.Lateral,
3533            this=this,
3534            view=view,
3535            outer=outer,
3536            alias=table_alias,
3537            cross_apply=cross_apply,
3538        )
3539
3540    def _parse_join_parts(
3541        self,
3542    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
3543        return (
3544            self._match_set(self.JOIN_METHODS) and self._prev,
3545            self._match_set(self.JOIN_SIDES) and self._prev,
3546            self._match_set(self.JOIN_KINDS) and self._prev,
3547        )
3548
3549    def _parse_using_identifiers(self) -> t.List[exp.Expression]:
3550        def _parse_column_as_identifier() -> t.Optional[exp.Expression]:
3551            this = self._parse_column()
3552            if isinstance(this, exp.Column):
3553                return this.this
3554            return this
3555
3556        return self._parse_wrapped_csv(_parse_column_as_identifier, optional=True)
3557
3558    def _parse_join(
3559        self, skip_join_token: bool = False, parse_bracket: bool = False
3560    ) -> t.Optional[exp.Join]:
3561        if self._match(TokenType.COMMA):
3562            return self.expression(exp.Join, this=self._parse_table())
3563
3564        index = self._index
3565        method, side, kind = self._parse_join_parts()
3566        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
3567        join = self._match(TokenType.JOIN) or (kind and kind.token_type == TokenType.STRAIGHT_JOIN)
3568
3569        if not skip_join_token and not join:
3570            self._retreat(index)
3571            kind = None
3572            method = None
3573            side = None
3574
3575        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
3576        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
3577
3578        if not skip_join_token and not join and not outer_apply and not cross_apply:
3579            return None
3580
3581        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table(parse_bracket=parse_bracket)}
3582        if kind and kind.token_type == TokenType.ARRAY and self._match(TokenType.COMMA):
3583            kwargs["expressions"] = self._parse_csv(
3584                lambda: self._parse_table(parse_bracket=parse_bracket)
3585            )
3586
3587        if method:
3588            kwargs["method"] = method.text
3589        if side:
3590            kwargs["side"] = side.text
3591        if kind:
3592            kwargs["kind"] = kind.text
3593        if hint:
3594            kwargs["hint"] = hint
3595
3596        if self._match(TokenType.MATCH_CONDITION):
3597            kwargs["match_condition"] = self._parse_wrapped(self._parse_comparison)
3598
3599        if self._match(TokenType.ON):
3600            kwargs["on"] = self._parse_assignment()
3601        elif self._match(TokenType.USING):
3602            kwargs["using"] = self._parse_using_identifiers()
3603        elif (
3604            not (outer_apply or cross_apply)
3605            and not isinstance(kwargs["this"], exp.Unnest)
3606            and not (kind and kind.token_type in (TokenType.CROSS, TokenType.ARRAY))
3607        ):
3608            index = self._index
3609            joins: t.Optional[list] = list(self._parse_joins())
3610
3611            if joins and self._match(TokenType.ON):
3612                kwargs["on"] = self._parse_assignment()
3613            elif joins and self._match(TokenType.USING):
3614                kwargs["using"] = self._parse_using_identifiers()
3615            else:
3616                joins = None
3617                self._retreat(index)
3618
3619            kwargs["this"].set("joins", joins if joins else None)
3620
3621        comments = [c for token in (method, side, kind) if token for c in token.comments]
3622        return self.expression(exp.Join, comments=comments, **kwargs)
3623
3624    def _parse_opclass(self) -> t.Optional[exp.Expression]:
3625        this = self._parse_assignment()
3626
3627        if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
3628            return this
3629
3630        if not self._match_set(self.OPTYPE_FOLLOW_TOKENS, advance=False):
3631            return self.expression(exp.Opclass, this=this, expression=self._parse_table_parts())
3632
3633        return this
3634
3635    def _parse_index_params(self) -> exp.IndexParameters:
3636        using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
3637
3638        if self._match(TokenType.L_PAREN, advance=False):
3639            columns = self._parse_wrapped_csv(self._parse_with_operator)
3640        else:
3641            columns = None
3642
3643        include = self._parse_wrapped_id_vars() if self._match_text_seq("INCLUDE") else None
3644        partition_by = self._parse_partition_by()
3645        with_storage = self._match(TokenType.WITH) and self._parse_wrapped_properties()
3646        tablespace = (
3647            self._parse_var(any_token=True)
3648            if self._match_text_seq("USING", "INDEX", "TABLESPACE")
3649            else None
3650        )
3651        where = self._parse_where()
3652
3653        on = self._parse_field() if self._match(TokenType.ON) else None
3654
3655        return self.expression(
3656            exp.IndexParameters,
3657            using=using,
3658            columns=columns,
3659            include=include,
3660            partition_by=partition_by,
3661            where=where,
3662            with_storage=with_storage,
3663            tablespace=tablespace,
3664            on=on,
3665        )
3666
3667    def _parse_index(
3668        self, index: t.Optional[exp.Expression] = None, anonymous: bool = False
3669    ) -> t.Optional[exp.Index]:
3670        if index or anonymous:
3671            unique = None
3672            primary = None
3673            amp = None
3674
3675            self._match(TokenType.ON)
3676            self._match(TokenType.TABLE)  # hive
3677            table = self._parse_table_parts(schema=True)
3678        else:
3679            unique = self._match(TokenType.UNIQUE)
3680            primary = self._match_text_seq("PRIMARY")
3681            amp = self._match_text_seq("AMP")
3682
3683            if not self._match(TokenType.INDEX):
3684                return None
3685
3686            index = self._parse_id_var()
3687            table = None
3688
3689        params = self._parse_index_params()
3690
3691        return self.expression(
3692            exp.Index,
3693            this=index,
3694            table=table,
3695            unique=unique,
3696            primary=primary,
3697            amp=amp,
3698            params=params,
3699        )
3700
3701    def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
3702        hints: t.List[exp.Expression] = []
3703        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
3704            # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
3705            hints.append(
3706                self.expression(
3707                    exp.WithTableHint,
3708                    expressions=self._parse_csv(
3709                        lambda: self._parse_function() or self._parse_var(any_token=True)
3710                    ),
3711                )
3712            )
3713            self._match_r_paren()
3714        else:
3715            # https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
3716            while self._match_set(self.TABLE_INDEX_HINT_TOKENS):
3717                hint = exp.IndexTableHint(this=self._prev.text.upper())
3718
3719                self._match_set((TokenType.INDEX, TokenType.KEY))
3720                if self._match(TokenType.FOR):
3721                    hint.set("target", self._advance_any() and self._prev.text.upper())
3722
3723                hint.set("expressions", self._parse_wrapped_id_vars())
3724                hints.append(hint)
3725
3726        return hints or None
3727
3728    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
3729        return (
3730            (not schema and self._parse_function(optional_parens=False))
3731            or self._parse_id_var(any_token=False)
3732            or self._parse_string_as_identifier()
3733            or self._parse_placeholder()
3734        )
3735
3736    def _parse_table_parts(
3737        self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
3738    ) -> exp.Table:
3739        catalog = None
3740        db = None
3741        table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
3742
3743        while self._match(TokenType.DOT):
3744            if catalog:
3745                # This allows nesting the table in arbitrarily many dot expressions if needed
3746                table = self.expression(
3747                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
3748                )
3749            else:
3750                catalog = db
3751                db = table
3752                # "" used for tsql FROM a..b case
3753                table = self._parse_table_part(schema=schema) or ""
3754
3755        if (
3756            wildcard
3757            and self._is_connected()
3758            and (isinstance(table, exp.Identifier) or not table)
3759            and self._match(TokenType.STAR)
3760        ):
3761            if isinstance(table, exp.Identifier):
3762                table.args["this"] += "*"
3763            else:
3764                table = exp.Identifier(this="*")
3765
3766        # We bubble up comments from the Identifier to the Table
3767        comments = table.pop_comments() if isinstance(table, exp.Expression) else None
3768
3769        if is_db_reference:
3770            catalog = db
3771            db = table
3772            table = None
3773
3774        if not table and not is_db_reference:
3775            self.raise_error(f"Expected table name but got {self._curr}")
3776        if not db and is_db_reference:
3777            self.raise_error(f"Expected database name but got {self._curr}")
3778
3779        table = self.expression(
3780            exp.Table,
3781            comments=comments,
3782            this=table,
3783            db=db,
3784            catalog=catalog,
3785        )
3786
3787        changes = self._parse_changes()
3788        if changes:
3789            table.set("changes", changes)
3790
3791        at_before = self._parse_historical_data()
3792        if at_before:
3793            table.set("when", at_before)
3794
3795        pivots = self._parse_pivots()
3796        if pivots:
3797            table.set("pivots", pivots)
3798
3799        return table
3800
3801    def _parse_table(
3802        self,
3803        schema: bool = False,
3804        joins: bool = False,
3805        alias_tokens: t.Optional[t.Collection[TokenType]] = None,
3806        parse_bracket: bool = False,
3807        is_db_reference: bool = False,
3808        parse_partition: bool = False,
3809    ) -> t.Optional[exp.Expression]:
3810        lateral = self._parse_lateral()
3811        if lateral:
3812            return lateral
3813
3814        unnest = self._parse_unnest()
3815        if unnest:
3816            return unnest
3817
3818        values = self._parse_derived_table_values()
3819        if values:
3820            return values
3821
3822        subquery = self._parse_select(table=True)
3823        if subquery:
3824            if not subquery.args.get("pivots"):
3825                subquery.set("pivots", self._parse_pivots())
3826            return subquery
3827
3828        bracket = parse_bracket and self._parse_bracket(None)
3829        bracket = self.expression(exp.Table, this=bracket) if bracket else None
3830
3831        rows_from = self._match_text_seq("ROWS", "FROM") and self._parse_wrapped_csv(
3832            self._parse_table
3833        )
3834        rows_from = self.expression(exp.Table, rows_from=rows_from) if rows_from else None
3835
3836        only = self._match(TokenType.ONLY)
3837
3838        this = t.cast(
3839            exp.Expression,
3840            bracket
3841            or rows_from
3842            or self._parse_bracket(
3843                self._parse_table_parts(schema=schema, is_db_reference=is_db_reference)
3844            ),
3845        )
3846
3847        if only:
3848            this.set("only", only)
3849
3850        # Postgres supports a wildcard (table) suffix operator, which is a no-op in this context
3851        self._match_text_seq("*")
3852
3853        parse_partition = parse_partition or self.SUPPORTS_PARTITION_SELECTION
3854        if parse_partition and self._match(TokenType.PARTITION, advance=False):
3855            this.set("partition", self._parse_partition())
3856
3857        if schema:
3858            return self._parse_schema(this=this)
3859
3860        version = self._parse_version()
3861
3862        if version:
3863            this.set("version", version)
3864
3865        if self.dialect.ALIAS_POST_TABLESAMPLE:
3866            this.set("sample", self._parse_table_sample())
3867
3868        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
3869        if alias:
3870            this.set("alias", alias)
3871
3872        if isinstance(this, exp.Table) and self._match_text_seq("AT"):
3873            return self.expression(
3874                exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
3875            )
3876
3877        this.set("hints", self._parse_table_hints())
3878
3879        if not this.args.get("pivots"):
3880            this.set("pivots", self._parse_pivots())
3881
3882        if not self.dialect.ALIAS_POST_TABLESAMPLE:
3883            this.set("sample", self._parse_table_sample())
3884
3885        if joins:
3886            for join in self._parse_joins():
3887                this.append("joins", join)
3888
3889        if self._match_pair(TokenType.WITH, TokenType.ORDINALITY):
3890            this.set("ordinality", True)
3891            this.set("alias", self._parse_table_alias())
3892
3893        return this
3894
3895    def _parse_version(self) -> t.Optional[exp.Version]:
3896        if self._match(TokenType.TIMESTAMP_SNAPSHOT):
3897            this = "TIMESTAMP"
3898        elif self._match(TokenType.VERSION_SNAPSHOT):
3899            this = "VERSION"
3900        else:
3901            return None
3902
3903        if self._match_set((TokenType.FROM, TokenType.BETWEEN)):
3904            kind = self._prev.text.upper()
3905            start = self._parse_bitwise()
3906            self._match_texts(("TO", "AND"))
3907            end = self._parse_bitwise()
3908            expression: t.Optional[exp.Expression] = self.expression(
3909                exp.Tuple, expressions=[start, end]
3910            )
3911        elif self._match_text_seq("CONTAINED", "IN"):
3912            kind = "CONTAINED IN"
3913            expression = self.expression(
3914                exp.Tuple, expressions=self._parse_wrapped_csv(self._parse_bitwise)
3915            )
3916        elif self._match(TokenType.ALL):
3917            kind = "ALL"
3918            expression = None
3919        else:
3920            self._match_text_seq("AS", "OF")
3921            kind = "AS OF"
3922            expression = self._parse_type()
3923
3924        return self.expression(exp.Version, this=this, expression=expression, kind=kind)
3925
3926    def _parse_historical_data(self) -> t.Optional[exp.HistoricalData]:
3927        # https://docs.snowflake.com/en/sql-reference/constructs/at-before
3928        index = self._index
3929        historical_data = None
3930        if self._match_texts(self.HISTORICAL_DATA_PREFIX):
3931            this = self._prev.text.upper()
3932            kind = (
3933                self._match(TokenType.L_PAREN)
3934                and self._match_texts(self.HISTORICAL_DATA_KIND)
3935                and self._prev.text.upper()
3936            )
3937            expression = self._match(TokenType.FARROW) and self._parse_bitwise()
3938
3939            if expression:
3940                self._match_r_paren()
3941                historical_data = self.expression(
3942                    exp.HistoricalData, this=this, kind=kind, expression=expression
3943                )
3944            else:
3945                self._retreat(index)
3946
3947        return historical_data
3948
3949    def _parse_changes(self) -> t.Optional[exp.Changes]:
3950        if not self._match_text_seq("CHANGES", "(", "INFORMATION", "=>"):
3951            return None
3952
3953        information = self._parse_var(any_token=True)
3954        self._match_r_paren()
3955
3956        return self.expression(
3957            exp.Changes,
3958            information=information,
3959            at_before=self._parse_historical_data(),
3960            end=self._parse_historical_data(),
3961        )
3962
3963    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
3964        if not self._match(TokenType.UNNEST):
3965            return None
3966
3967        expressions = self._parse_wrapped_csv(self._parse_equality)
3968        offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
3969
3970        alias = self._parse_table_alias() if with_alias else None
3971
3972        if alias:
3973            if self.dialect.UNNEST_COLUMN_ONLY:
3974                if alias.args.get("columns"):
3975                    self.raise_error("Unexpected extra column alias in unnest.")
3976
3977                alias.set("columns", [alias.this])
3978                alias.set("this", None)
3979
3980            columns = alias.args.get("columns") or []
3981            if offset and len(expressions) < len(columns):
3982                offset = columns.pop()
3983
3984        if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
3985            self._match(TokenType.ALIAS)
3986            offset = self._parse_id_var(
3987                any_token=False, tokens=self.UNNEST_OFFSET_ALIAS_TOKENS
3988            ) or exp.to_identifier("offset")
3989
3990        return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
3991
3992    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
3993        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
3994        if not is_derived and not (
3995            # ClickHouse's `FORMAT Values` is equivalent to `VALUES`
3996            self._match_text_seq("VALUES") or self._match_text_seq("FORMAT", "VALUES")
3997        ):
3998            return None
3999
4000        expressions = self._parse_csv(self._parse_value)
4001        alias = self._parse_table_alias()
4002
4003        if is_derived:
4004            self._match_r_paren()
4005
4006        return self.expression(
4007            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
4008        )
4009
4010    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
4011        if not self._match(TokenType.TABLE_SAMPLE) and not (
4012            as_modifier and self._match_text_seq("USING", "SAMPLE")
4013        ):
4014            return None
4015
4016        bucket_numerator = None
4017        bucket_denominator = None
4018        bucket_field = None
4019        percent = None
4020        size = None
4021        seed = None
4022
4023        method = self._parse_var(tokens=(TokenType.ROW,), upper=True)
4024        matched_l_paren = self._match(TokenType.L_PAREN)
4025
4026        if self.TABLESAMPLE_CSV:
4027            num = None
4028            expressions = self._parse_csv(self._parse_primary)
4029        else:
4030            expressions = None
4031            num = (
4032                self._parse_factor()
4033                if self._match(TokenType.NUMBER, advance=False)
4034                else self._parse_primary() or self._parse_placeholder()
4035            )
4036
4037        if self._match_text_seq("BUCKET"):
4038            bucket_numerator = self._parse_number()
4039            self._match_text_seq("OUT", "OF")
4040            bucket_denominator = bucket_denominator = self._parse_number()
4041            self._match(TokenType.ON)
4042            bucket_field = self._parse_field()
4043        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
4044            percent = num
4045        elif self._match(TokenType.ROWS) or not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
4046            size = num
4047        else:
4048            percent = num
4049
4050        if matched_l_paren:
4051            self._match_r_paren()
4052
4053        if self._match(TokenType.L_PAREN):
4054            method = self._parse_var(upper=True)
4055            seed = self._match(TokenType.COMMA) and self._parse_number()
4056            self._match_r_paren()
4057        elif self._match_texts(("SEED", "REPEATABLE")):
4058            seed = self._parse_wrapped(self._parse_number)
4059
4060        if not method and self.DEFAULT_SAMPLING_METHOD:
4061            method = exp.var(self.DEFAULT_SAMPLING_METHOD)
4062
4063        return self.expression(
4064            exp.TableSample,
4065            expressions=expressions,
4066            method=method,
4067            bucket_numerator=bucket_numerator,
4068            bucket_denominator=bucket_denominator,
4069            bucket_field=bucket_field,
4070            percent=percent,
4071            size=size,
4072            seed=seed,
4073        )
4074
4075    def _parse_pivots(self) -> t.Optional[t.List[exp.Pivot]]:
4076        return list(iter(self._parse_pivot, None)) or None
4077
4078    def _parse_joins(self) -> t.Iterator[exp.Join]:
4079        return iter(self._parse_join, None)
4080
4081    def _parse_unpivot_columns(self) -> t.Optional[exp.UnpivotColumns]:
4082        if not self._match(TokenType.INTO):
4083            return None
4084
4085        return self.expression(
4086            exp.UnpivotColumns,
4087            this=self._match_text_seq("NAME") and self._parse_column(),
4088            expressions=self._match_text_seq("VALUE") and self._parse_csv(self._parse_column),
4089        )
4090
4091    # https://duckdb.org/docs/sql/statements/pivot
4092    def _parse_simplified_pivot(self, is_unpivot: t.Optional[bool] = None) -> exp.Pivot:
4093        def _parse_on() -> t.Optional[exp.Expression]:
4094            this = self._parse_bitwise()
4095
4096            if self._match(TokenType.IN):
4097                # PIVOT ... ON col IN (row_val1, row_val2)
4098                return self._parse_in(this)
4099            if self._match(TokenType.ALIAS, advance=False):
4100                # UNPIVOT ... ON (col1, col2, col3) AS row_val
4101                return self._parse_alias(this)
4102
4103            return this
4104
4105        this = self._parse_table()
4106        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
4107        into = self._parse_unpivot_columns()
4108        using = self._match(TokenType.USING) and self._parse_csv(
4109            lambda: self._parse_alias(self._parse_function())
4110        )
4111        group = self._parse_group()
4112
4113        return self.expression(
4114            exp.Pivot,
4115            this=this,
4116            expressions=expressions,
4117            using=using,
4118            group=group,
4119            unpivot=is_unpivot,
4120            into=into,
4121        )
4122
4123    def _parse_pivot_in(self) -> exp.In | exp.PivotAny:
4124        def _parse_aliased_expression() -> t.Optional[exp.Expression]:
4125            this = self._parse_select_or_expression()
4126
4127            self._match(TokenType.ALIAS)
4128            alias = self._parse_bitwise()
4129            if alias:
4130                if isinstance(alias, exp.Column) and not alias.db:
4131                    alias = alias.this
4132                return self.expression(exp.PivotAlias, this=this, alias=alias)
4133
4134            return this
4135
4136        value = self._parse_column()
4137
4138        if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
4139            self.raise_error("Expecting IN (")
4140
4141        if self._match(TokenType.ANY):
4142            exprs: t.List[exp.Expression] = ensure_list(exp.PivotAny(this=self._parse_order()))
4143        else:
4144            exprs = self._parse_csv(_parse_aliased_expression)
4145
4146        self._match_r_paren()
4147        return self.expression(exp.In, this=value, expressions=exprs)
4148
4149    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
4150        index = self._index
4151        include_nulls = None
4152
4153        if self._match(TokenType.PIVOT):
4154            unpivot = False
4155        elif self._match(TokenType.UNPIVOT):
4156            unpivot = True
4157
4158            # https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
4159            if self._match_text_seq("INCLUDE", "NULLS"):
4160                include_nulls = True
4161            elif self._match_text_seq("EXCLUDE", "NULLS"):
4162                include_nulls = False
4163        else:
4164            return None
4165
4166        expressions = []
4167
4168        if not self._match(TokenType.L_PAREN):
4169            self._retreat(index)
4170            return None
4171
4172        if unpivot:
4173            expressions = self._parse_csv(self._parse_column)
4174        else:
4175            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
4176
4177        if not expressions:
4178            self.raise_error("Failed to parse PIVOT's aggregation list")
4179
4180        if not self._match(TokenType.FOR):
4181            self.raise_error("Expecting FOR")
4182
4183        field = self._parse_pivot_in()
4184        default_on_null = self._match_text_seq("DEFAULT", "ON", "NULL") and self._parse_wrapped(
4185            self._parse_bitwise
4186        )
4187
4188        self._match_r_paren()
4189
4190        pivot = self.expression(
4191            exp.Pivot,
4192            expressions=expressions,
4193            field=field,
4194            unpivot=unpivot,
4195            include_nulls=include_nulls,
4196            default_on_null=default_on_null,
4197        )
4198
4199        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
4200            pivot.set("alias", self._parse_table_alias())
4201
4202        if not unpivot:
4203            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
4204
4205            columns: t.List[exp.Expression] = []
4206            for fld in pivot.args["field"].expressions:
4207                field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
4208                for name in names:
4209                    if self.PREFIXED_PIVOT_COLUMNS:
4210                        name = f"{name}_{field_name}" if name else field_name
4211                    else:
4212                        name = f"{field_name}_{name}" if name else field_name
4213
4214                    columns.append(exp.to_identifier(name))
4215
4216            pivot.set("columns", columns)
4217
4218        return pivot
4219
4220    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
4221        return [agg.alias for agg in aggregations]
4222
4223    def _parse_prewhere(self, skip_where_token: bool = False) -> t.Optional[exp.PreWhere]:
4224        if not skip_where_token and not self._match(TokenType.PREWHERE):
4225            return None
4226
4227        return self.expression(
4228            exp.PreWhere, comments=self._prev_comments, this=self._parse_assignment()
4229        )
4230
4231    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
4232        if not skip_where_token and not self._match(TokenType.WHERE):
4233            return None
4234
4235        return self.expression(
4236            exp.Where, comments=self._prev_comments, this=self._parse_assignment()
4237        )
4238
4239    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
4240        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
4241            return None
4242
4243        elements: t.Dict[str, t.Any] = defaultdict(list)
4244
4245        if self._match(TokenType.ALL):
4246            elements["all"] = True
4247        elif self._match(TokenType.DISTINCT):
4248            elements["all"] = False
4249
4250        while True:
4251            index = self._index
4252
4253            elements["expressions"].extend(
4254                self._parse_csv(
4255                    lambda: None
4256                    if self._match_set((TokenType.CUBE, TokenType.ROLLUP), advance=False)
4257                    else self._parse_assignment()
4258                )
4259            )
4260
4261            before_with_index = self._index
4262            with_prefix = self._match(TokenType.WITH)
4263
4264            if self._match(TokenType.ROLLUP):
4265                elements["rollup"].append(
4266                    self._parse_cube_or_rollup(exp.Rollup, with_prefix=with_prefix)
4267                )
4268            elif self._match(TokenType.CUBE):
4269                elements["cube"].append(
4270                    self._parse_cube_or_rollup(exp.Cube, with_prefix=with_prefix)
4271                )
4272            elif self._match(TokenType.GROUPING_SETS):
4273                elements["grouping_sets"].append(
4274                    self.expression(
4275                        exp.GroupingSets,
4276                        expressions=self._parse_wrapped_csv(self._parse_grouping_set),
4277                    )
4278                )
4279            elif self._match_text_seq("TOTALS"):
4280                elements["totals"] = True  # type: ignore
4281
4282            if before_with_index <= self._index <= before_with_index + 1:
4283                self._retreat(before_with_index)
4284                break
4285
4286            if index == self._index:
4287                break
4288
4289        return self.expression(exp.Group, **elements)  # type: ignore
4290
4291    def _parse_cube_or_rollup(self, kind: t.Type[E], with_prefix: bool = False) -> E:
4292        return self.expression(
4293            kind, expressions=[] if with_prefix else self._parse_wrapped_csv(self._parse_column)
4294        )
4295
4296    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
4297        if self._match(TokenType.L_PAREN):
4298            grouping_set = self._parse_csv(self._parse_column)
4299            self._match_r_paren()
4300            return self.expression(exp.Tuple, expressions=grouping_set)
4301
4302        return self._parse_column()
4303
4304    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
4305        if not skip_having_token and not self._match(TokenType.HAVING):
4306            return None
4307        return self.expression(exp.Having, this=self._parse_assignment())
4308
4309    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
4310        if not self._match(TokenType.QUALIFY):
4311            return None
4312        return self.expression(exp.Qualify, this=self._parse_assignment())
4313
4314    def _parse_connect(self, skip_start_token: bool = False) -> t.Optional[exp.Connect]:
4315        if skip_start_token:
4316            start = None
4317        elif self._match(TokenType.START_WITH):
4318            start = self._parse_assignment()
4319        else:
4320            return None
4321
4322        self._match(TokenType.CONNECT_BY)
4323        nocycle = self._match_text_seq("NOCYCLE")
4324        self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
4325            exp.Prior, this=self._parse_bitwise()
4326        )
4327        connect = self._parse_assignment()
4328        self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
4329
4330        if not start and self._match(TokenType.START_WITH):
4331            start = self._parse_assignment()
4332
4333        return self.expression(exp.Connect, start=start, connect=connect, nocycle=nocycle)
4334
4335    def _parse_name_as_expression(self) -> t.Optional[exp.Expression]:
4336        this = self._parse_id_var(any_token=True)
4337        if self._match(TokenType.ALIAS):
4338            this = self.expression(exp.Alias, alias=this, this=self._parse_assignment())
4339        return this
4340
4341    def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
4342        if self._match_text_seq("INTERPOLATE"):
4343            return self._parse_wrapped_csv(self._parse_name_as_expression)
4344        return None
4345
4346    def _parse_order(
4347        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
4348    ) -> t.Optional[exp.Expression]:
4349        siblings = None
4350        if not skip_order_token and not self._match(TokenType.ORDER_BY):
4351            if not self._match(TokenType.ORDER_SIBLINGS_BY):
4352                return this
4353
4354            siblings = True
4355
4356        return self.expression(
4357            exp.Order,
4358            this=this,
4359            expressions=self._parse_csv(self._parse_ordered),
4360            siblings=siblings,
4361        )
4362
4363    def _parse_sort(self, exp_class: t.Type[E], token: TokenType) -> t.Optional[E]:
4364        if not self._match(token):
4365            return None
4366        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
4367
4368    def _parse_ordered(
4369        self, parse_method: t.Optional[t.Callable] = None
4370    ) -> t.Optional[exp.Ordered]:
4371        this = parse_method() if parse_method else self._parse_assignment()
4372        if not this:
4373            return None
4374
4375        if this.name.upper() == "ALL" and self.dialect.SUPPORTS_ORDER_BY_ALL:
4376            this = exp.var("ALL")
4377
4378        asc = self._match(TokenType.ASC)
4379        desc = self._match(TokenType.DESC) or (asc and False)
4380
4381        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
4382        is_nulls_last = self._match_text_seq("NULLS", "LAST")
4383
4384        nulls_first = is_nulls_first or False
4385        explicitly_null_ordered = is_nulls_first or is_nulls_last
4386
4387        if (
4388            not explicitly_null_ordered
4389            and (
4390                (not desc and self.dialect.NULL_ORDERING == "nulls_are_small")
4391                or (desc and self.dialect.NULL_ORDERING != "nulls_are_small")
4392            )
4393            and self.dialect.NULL_ORDERING != "nulls_are_last"
4394        ):
4395            nulls_first = True
4396
4397        if self._match_text_seq("WITH", "FILL"):
4398            with_fill = self.expression(
4399                exp.WithFill,
4400                **{  # type: ignore
4401                    "from": self._match(TokenType.FROM) and self._parse_bitwise(),
4402                    "to": self._match_text_seq("TO") and self._parse_bitwise(),
4403                    "step": self._match_text_seq("STEP") and self._parse_bitwise(),
4404                    "interpolate": self._parse_interpolate(),
4405                },
4406            )
4407        else:
4408            with_fill = None
4409
4410        return self.expression(
4411            exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
4412        )
4413
4414    def _parse_limit(
4415        self,
4416        this: t.Optional[exp.Expression] = None,
4417        top: bool = False,
4418        skip_limit_token: bool = False,
4419    ) -> t.Optional[exp.Expression]:
4420        if skip_limit_token or self._match(TokenType.TOP if top else TokenType.LIMIT):
4421            comments = self._prev_comments
4422            if top:
4423                limit_paren = self._match(TokenType.L_PAREN)
4424                expression = self._parse_term() if limit_paren else self._parse_number()
4425
4426                if limit_paren:
4427                    self._match_r_paren()
4428            else:
4429                expression = self._parse_term()
4430
4431            if self._match(TokenType.COMMA):
4432                offset = expression
4433                expression = self._parse_term()
4434            else:
4435                offset = None
4436
4437            limit_exp = self.expression(
4438                exp.Limit,
4439                this=this,
4440                expression=expression,
4441                offset=offset,
4442                comments=comments,
4443                expressions=self._parse_limit_by(),
4444            )
4445
4446            return limit_exp
4447
4448        if self._match(TokenType.FETCH):
4449            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
4450            direction = self._prev.text.upper() if direction else "FIRST"
4451
4452            count = self._parse_field(tokens=self.FETCH_TOKENS)
4453            percent = self._match(TokenType.PERCENT)
4454
4455            self._match_set((TokenType.ROW, TokenType.ROWS))
4456
4457            only = self._match_text_seq("ONLY")
4458            with_ties = self._match_text_seq("WITH", "TIES")
4459
4460            if only and with_ties:
4461                self.raise_error("Cannot specify both ONLY and WITH TIES in FETCH clause")
4462
4463            return self.expression(
4464                exp.Fetch,
4465                direction=direction,
4466                count=count,
4467                percent=percent,
4468                with_ties=with_ties,
4469            )
4470
4471        return this
4472
4473    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4474        if not self._match(TokenType.OFFSET):
4475            return this
4476
4477        count = self._parse_term()
4478        self._match_set((TokenType.ROW, TokenType.ROWS))
4479
4480        return self.expression(
4481            exp.Offset, this=this, expression=count, expressions=self._parse_limit_by()
4482        )
4483
4484    def _can_parse_limit_or_offset(self) -> bool:
4485        if not self._match_set(self.AMBIGUOUS_ALIAS_TOKENS, advance=False):
4486            return False
4487
4488        index = self._index
4489        result = bool(
4490            self._try_parse(self._parse_limit, retreat=True)
4491            or self._try_parse(self._parse_offset, retreat=True)
4492        )
4493        self._retreat(index)
4494        return result
4495
4496    def _parse_limit_by(self) -> t.Optional[t.List[exp.Expression]]:
4497        return self._match_text_seq("BY") and self._parse_csv(self._parse_bitwise)
4498
4499    def _parse_locks(self) -> t.List[exp.Lock]:
4500        locks = []
4501        while True:
4502            if self._match_text_seq("FOR", "UPDATE"):
4503                update = True
4504            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
4505                "LOCK", "IN", "SHARE", "MODE"
4506            ):
4507                update = False
4508            else:
4509                break
4510
4511            expressions = None
4512            if self._match_text_seq("OF"):
4513                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
4514
4515            wait: t.Optional[bool | exp.Expression] = None
4516            if self._match_text_seq("NOWAIT"):
4517                wait = True
4518            elif self._match_text_seq("WAIT"):
4519                wait = self._parse_primary()
4520            elif self._match_text_seq("SKIP", "LOCKED"):
4521                wait = False
4522
4523            locks.append(
4524                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
4525            )
4526
4527        return locks
4528
4529    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4530        while this and self._match_set(self.SET_OPERATIONS):
4531            token_type = self._prev.token_type
4532
4533            if token_type == TokenType.UNION:
4534                operation: t.Type[exp.SetOperation] = exp.Union
4535            elif token_type == TokenType.EXCEPT:
4536                operation = exp.Except
4537            else:
4538                operation = exp.Intersect
4539
4540            comments = self._prev.comments
4541
4542            if self._match(TokenType.DISTINCT):
4543                distinct: t.Optional[bool] = True
4544            elif self._match(TokenType.ALL):
4545                distinct = False
4546            else:
4547                distinct = self.dialect.SET_OP_DISTINCT_BY_DEFAULT[operation]
4548                if distinct is None:
4549                    self.raise_error(f"Expected DISTINCT or ALL for {operation.__name__}")
4550
4551            by_name = self._match_text_seq("BY", "NAME")
4552            expression = self._parse_select(nested=True, parse_set_operation=False)
4553
4554            this = self.expression(
4555                operation,
4556                comments=comments,
4557                this=this,
4558                distinct=distinct,
4559                by_name=by_name,
4560                expression=expression,
4561            )
4562
4563        if isinstance(this, exp.SetOperation) and self.MODIFIERS_ATTACHED_TO_SET_OP:
4564            expression = this.expression
4565
4566            if expression:
4567                for arg in self.SET_OP_MODIFIERS:
4568                    expr = expression.args.get(arg)
4569                    if expr:
4570                        this.set(arg, expr.pop())
4571
4572        return this
4573
4574    def _parse_expression(self) -> t.Optional[exp.Expression]:
4575        return self._parse_alias(self._parse_assignment())
4576
4577    def _parse_assignment(self) -> t.Optional[exp.Expression]:
4578        this = self._parse_disjunction()
4579        if not this and self._next and self._next.token_type in self.ASSIGNMENT:
4580            # This allows us to parse <non-identifier token> := <expr>
4581            this = exp.column(
4582                t.cast(str, self._advance_any(ignore_reserved=True) and self._prev.text)
4583            )
4584
4585        while self._match_set(self.ASSIGNMENT):
4586            if isinstance(this, exp.Column) and len(this.parts) == 1:
4587                this = this.this
4588
4589            this = self.expression(
4590                self.ASSIGNMENT[self._prev.token_type],
4591                this=this,
4592                comments=self._prev_comments,
4593                expression=self._parse_assignment(),
4594            )
4595
4596        return this
4597
4598    def _parse_disjunction(self) -> t.Optional[exp.Expression]:
4599        return self._parse_tokens(self._parse_conjunction, self.DISJUNCTION)
4600
4601    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
4602        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
4603
4604    def _parse_equality(self) -> t.Optional[exp.Expression]:
4605        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
4606
4607    def _parse_comparison(self) -> t.Optional[exp.Expression]:
4608        return self._parse_tokens(self._parse_range, self.COMPARISON)
4609
4610    def _parse_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4611        this = this or self._parse_bitwise()
4612        negate = self._match(TokenType.NOT)
4613
4614        if self._match_set(self.RANGE_PARSERS):
4615            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
4616            if not expression:
4617                return this
4618
4619            this = expression
4620        elif self._match(TokenType.ISNULL):
4621            this = self.expression(exp.Is, this=this, expression=exp.Null())
4622
4623        # Postgres supports ISNULL and NOTNULL for conditions.
4624        # https://blog.andreiavram.ro/postgresql-null-composite-type/
4625        if self._match(TokenType.NOTNULL):
4626            this = self.expression(exp.Is, this=this, expression=exp.Null())
4627            this = self.expression(exp.Not, this=this)
4628
4629        if negate:
4630            this = self._negate_range(this)
4631
4632        if self._match(TokenType.IS):
4633            this = self._parse_is(this)
4634
4635        return this
4636
4637    def _negate_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4638        if not this:
4639            return this
4640
4641        return self.expression(exp.Not, this=this)
4642
4643    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4644        index = self._index - 1
4645        negate = self._match(TokenType.NOT)
4646
4647        if self._match_text_seq("DISTINCT", "FROM"):
4648            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
4649            return self.expression(klass, this=this, expression=self._parse_bitwise())
4650
4651        if self._match(TokenType.JSON):
4652            kind = self._match_texts(self.IS_JSON_PREDICATE_KIND) and self._prev.text.upper()
4653
4654            if self._match_text_seq("WITH"):
4655                _with = True
4656            elif self._match_text_seq("WITHOUT"):
4657                _with = False
4658            else:
4659                _with = None
4660
4661            unique = self._match(TokenType.UNIQUE)
4662            self._match_text_seq("KEYS")
4663            expression: t.Optional[exp.Expression] = self.expression(
4664                exp.JSON, **{"this": kind, "with": _with, "unique": unique}
4665            )
4666        else:
4667            expression = self._parse_primary() or self._parse_null()
4668            if not expression:
4669                self._retreat(index)
4670                return None
4671
4672        this = self.expression(exp.Is, this=this, expression=expression)
4673        return self.expression(exp.Not, this=this) if negate else this
4674
4675    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
4676        unnest = self._parse_unnest(with_alias=False)
4677        if unnest:
4678            this = self.expression(exp.In, this=this, unnest=unnest)
4679        elif self._match_set((TokenType.L_PAREN, TokenType.L_BRACKET)):
4680            matched_l_paren = self._prev.token_type == TokenType.L_PAREN
4681            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
4682
4683            if len(expressions) == 1 and isinstance(expressions[0], exp.Query):
4684                this = self.expression(exp.In, this=this, query=expressions[0].subquery(copy=False))
4685            else:
4686                this = self.expression(exp.In, this=this, expressions=expressions)
4687
4688            if matched_l_paren:
4689                self._match_r_paren(this)
4690            elif not self._match(TokenType.R_BRACKET, expression=this):
4691                self.raise_error("Expecting ]")
4692        else:
4693            this = self.expression(exp.In, this=this, field=self._parse_column())
4694
4695        return this
4696
4697    def _parse_between(self, this: t.Optional[exp.Expression]) -> exp.Between:
4698        low = self._parse_bitwise()
4699        self._match(TokenType.AND)
4700        high = self._parse_bitwise()
4701        return self.expression(exp.Between, this=this, low=low, high=high)
4702
4703    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4704        if not self._match(TokenType.ESCAPE):
4705            return this
4706        return self.expression(exp.Escape, this=this, expression=self._parse_string())
4707
4708    def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Add | exp.Interval]:
4709        index = self._index
4710
4711        if not self._match(TokenType.INTERVAL) and match_interval:
4712            return None
4713
4714        if self._match(TokenType.STRING, advance=False):
4715            this = self._parse_primary()
4716        else:
4717            this = self._parse_term()
4718
4719        if not this or (
4720            isinstance(this, exp.Column)
4721            and not this.table
4722            and not this.this.quoted
4723            and this.name.upper() == "IS"
4724        ):
4725            self._retreat(index)
4726            return None
4727
4728        unit = self._parse_function() or (
4729            not self._match(TokenType.ALIAS, advance=False)
4730            and self._parse_var(any_token=True, upper=True)
4731        )
4732
4733        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
4734        # each INTERVAL expression into this canonical form so it's easy to transpile
4735        if this and this.is_number:
4736            this = exp.Literal.string(this.to_py())
4737        elif this and this.is_string:
4738            parts = exp.INTERVAL_STRING_RE.findall(this.name)
4739            if parts and unit:
4740                # Unconsume the eagerly-parsed unit, since the real unit was part of the string
4741                unit = None
4742                self._retreat(self._index - 1)
4743
4744            if len(parts) == 1:
4745                this = exp.Literal.string(parts[0][0])
4746                unit = self.expression(exp.Var, this=parts[0][1].upper())
4747        if self.INTERVAL_SPANS and self._match_text_seq("TO"):
4748            unit = self.expression(
4749                exp.IntervalSpan, this=unit, expression=self._parse_var(any_token=True, upper=True)
4750            )
4751
4752        interval = self.expression(exp.Interval, this=this, unit=unit)
4753
4754        index = self._index
4755        self._match(TokenType.PLUS)
4756
4757        # Convert INTERVAL 'val_1' unit_1 [+] ... [+] 'val_n' unit_n into a sum of intervals
4758        if self._match_set((TokenType.STRING, TokenType.NUMBER), advance=False):
4759            return self.expression(
4760                exp.Add, this=interval, expression=self._parse_interval(match_interval=False)
4761            )
4762
4763        self._retreat(index)
4764        return interval
4765
4766    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
4767        this = self._parse_term()
4768
4769        while True:
4770            if self._match_set(self.BITWISE):
4771                this = self.expression(
4772                    self.BITWISE[self._prev.token_type],
4773                    this=this,
4774                    expression=self._parse_term(),
4775                )
4776            elif self.dialect.DPIPE_IS_STRING_CONCAT and self._match(TokenType.DPIPE):
4777                this = self.expression(
4778                    exp.DPipe,
4779                    this=this,
4780                    expression=self._parse_term(),
4781                    safe=not self.dialect.STRICT_STRING_CONCAT,
4782                )
4783            elif self._match(TokenType.DQMARK):
4784                this = self.expression(
4785                    exp.Coalesce, this=this, expressions=ensure_list(self._parse_term())
4786                )
4787            elif self._match_pair(TokenType.LT, TokenType.LT):
4788                this = self.expression(
4789                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
4790                )
4791            elif self._match_pair(TokenType.GT, TokenType.GT):
4792                this = self.expression(
4793                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
4794                )
4795            else:
4796                break
4797
4798        return this
4799
4800    def _parse_term(self) -> t.Optional[exp.Expression]:
4801        this = self._parse_factor()
4802
4803        while self._match_set(self.TERM):
4804            klass = self.TERM[self._prev.token_type]
4805            comments = self._prev_comments
4806            expression = self._parse_factor()
4807
4808            this = self.expression(klass, this=this, comments=comments, expression=expression)
4809
4810            if isinstance(this, exp.Collate):
4811                expr = this.expression
4812
4813                # Preserve collations such as pg_catalog."default" (Postgres) as columns, otherwise
4814                # fallback to Identifier / Var
4815                if isinstance(expr, exp.Column) and len(expr.parts) == 1:
4816                    ident = expr.this
4817                    if isinstance(ident, exp.Identifier):
4818                        this.set("expression", ident if ident.quoted else exp.var(ident.name))
4819
4820        return this
4821
4822    def _parse_factor(self) -> t.Optional[exp.Expression]:
4823        parse_method = self._parse_exponent if self.EXPONENT else self._parse_unary
4824        this = parse_method()
4825
4826        while self._match_set(self.FACTOR):
4827            klass = self.FACTOR[self._prev.token_type]
4828            comments = self._prev_comments
4829            expression = parse_method()
4830
4831            if not expression and klass is exp.IntDiv and self._prev.text.isalpha():
4832                self._retreat(self._index - 1)
4833                return this
4834
4835            this = self.expression(klass, this=this, comments=comments, expression=expression)
4836
4837            if isinstance(this, exp.Div):
4838                this.args["typed"] = self.dialect.TYPED_DIVISION
4839                this.args["safe"] = self.dialect.SAFE_DIVISION
4840
4841        return this
4842
4843    def _parse_exponent(self) -> t.Optional[exp.Expression]:
4844        return self._parse_tokens(self._parse_unary, self.EXPONENT)
4845
4846    def _parse_unary(self) -> t.Optional[exp.Expression]:
4847        if self._match_set(self.UNARY_PARSERS):
4848            return self.UNARY_PARSERS[self._prev.token_type](self)
4849        return self._parse_at_time_zone(self._parse_type())
4850
4851    def _parse_type(
4852        self, parse_interval: bool = True, fallback_to_identifier: bool = False
4853    ) -> t.Optional[exp.Expression]:
4854        interval = parse_interval and self._parse_interval()
4855        if interval:
4856            return interval
4857
4858        index = self._index
4859        data_type = self._parse_types(check_func=True, allow_identifiers=False)
4860
4861        # parse_types() returns a Cast if we parsed BQ's inline constructor <type>(<values>) e.g.
4862        # STRUCT<a INT, b STRING>(1, 'foo'), which is canonicalized to CAST(<values> AS <type>)
4863        if isinstance(data_type, exp.Cast):
4864            # This constructor can contain ops directly after it, for instance struct unnesting:
4865            # STRUCT<a INT, b STRING>(1, 'foo').* --> CAST(STRUCT(1, 'foo') AS STRUCT<a iNT, b STRING).*
4866            return self._parse_column_ops(data_type)
4867
4868        if data_type:
4869            index2 = self._index
4870            this = self._parse_primary()
4871
4872            if isinstance(this, exp.Literal):
4873                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
4874                if parser:
4875                    return parser(self, this, data_type)
4876
4877                return self.expression(exp.Cast, this=this, to=data_type)
4878
4879            # The expressions arg gets set by the parser when we have something like DECIMAL(38, 0)
4880            # in the input SQL. In that case, we'll produce these tokens: DECIMAL ( 38 , 0 )
4881            #
4882            # If the index difference here is greater than 1, that means the parser itself must have
4883            # consumed additional tokens such as the DECIMAL scale and precision in the above example.
4884            #
4885            # If it's not greater than 1, then it must be 1, because we've consumed at least the type
4886            # keyword, meaning that the expressions arg of the DataType must have gotten set by a
4887            # callable in the TYPE_CONVERTERS mapping. For example, Snowflake converts DECIMAL to
4888            # DECIMAL(38, 0)) in order to facilitate the data type's transpilation.
4889            #
4890            # In these cases, we don't really want to return the converted type, but instead retreat
4891            # and try to parse a Column or Identifier in the section below.
4892            if data_type.expressions and index2 - index > 1:
4893                self._retreat(index2)
4894                return self._parse_column_ops(data_type)
4895
4896            self._retreat(index)
4897
4898        if fallback_to_identifier:
4899            return self._parse_id_var()
4900
4901        this = self._parse_column()
4902        return this and self._parse_column_ops(this)
4903
4904    def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
4905        this = self._parse_type()
4906        if not this:
4907            return None
4908
4909        if isinstance(this, exp.Column) and not this.table:
4910            this = exp.var(this.name.upper())
4911
4912        return self.expression(
4913            exp.DataTypeParam, this=this, expression=self._parse_var(any_token=True)
4914        )
4915
4916    def _parse_types(
4917        self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
4918    ) -> t.Optional[exp.Expression]:
4919        index = self._index
4920
4921        this: t.Optional[exp.Expression] = None
4922        prefix = self._match_text_seq("SYSUDTLIB", ".")
4923
4924        if not self._match_set(self.TYPE_TOKENS):
4925            identifier = allow_identifiers and self._parse_id_var(
4926                any_token=False, tokens=(TokenType.VAR,)
4927            )
4928            if isinstance(identifier, exp.Identifier):
4929                tokens = self.dialect.tokenize(identifier.sql(dialect=self.dialect))
4930
4931                if len(tokens) != 1:
4932                    self.raise_error("Unexpected identifier", self._prev)
4933
4934                if tokens[0].token_type in self.TYPE_TOKENS:
4935                    self._prev = tokens[0]
4936                elif self.dialect.SUPPORTS_USER_DEFINED_TYPES:
4937                    type_name = identifier.name
4938
4939                    while self._match(TokenType.DOT):
4940                        type_name = f"{type_name}.{self._advance_any() and self._prev.text}"
4941
4942                    this = exp.DataType.build(type_name, udt=True)
4943                else:
4944                    self._retreat(self._index - 1)
4945                    return None
4946            else:
4947                return None
4948
4949        type_token = self._prev.token_type
4950
4951        if type_token == TokenType.PSEUDO_TYPE:
4952            return self.expression(exp.PseudoType, this=self._prev.text.upper())
4953
4954        if type_token == TokenType.OBJECT_IDENTIFIER:
4955            return self.expression(exp.ObjectIdentifier, this=self._prev.text.upper())
4956
4957        # https://materialize.com/docs/sql/types/map/
4958        if type_token == TokenType.MAP and self._match(TokenType.L_BRACKET):
4959            key_type = self._parse_types(
4960                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4961            )
4962            if not self._match(TokenType.FARROW):
4963                self._retreat(index)
4964                return None
4965
4966            value_type = self._parse_types(
4967                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4968            )
4969            if not self._match(TokenType.R_BRACKET):
4970                self._retreat(index)
4971                return None
4972
4973            return exp.DataType(
4974                this=exp.DataType.Type.MAP,
4975                expressions=[key_type, value_type],
4976                nested=True,
4977                prefix=prefix,
4978            )
4979
4980        nested = type_token in self.NESTED_TYPE_TOKENS
4981        is_struct = type_token in self.STRUCT_TYPE_TOKENS
4982        is_aggregate = type_token in self.AGGREGATE_TYPE_TOKENS
4983        expressions = None
4984        maybe_func = False
4985
4986        if self._match(TokenType.L_PAREN):
4987            if is_struct:
4988                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
4989            elif nested:
4990                expressions = self._parse_csv(
4991                    lambda: self._parse_types(
4992                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4993                    )
4994                )
4995                if type_token == TokenType.NULLABLE and len(expressions) == 1:
4996                    this = expressions[0]
4997                    this.set("nullable", True)
4998                    self._match_r_paren()
4999                    return this
5000            elif type_token in self.ENUM_TYPE_TOKENS:
5001                expressions = self._parse_csv(self._parse_equality)
5002            elif is_aggregate:
5003                func_or_ident = self._parse_function(anonymous=True) or self._parse_id_var(
5004                    any_token=False, tokens=(TokenType.VAR,)
5005                )
5006                if not func_or_ident or not self._match(TokenType.COMMA):
5007                    return None
5008                expressions = self._parse_csv(
5009                    lambda: self._parse_types(
5010                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
5011                    )
5012                )
5013                expressions.insert(0, func_or_ident)
5014            else:
5015                expressions = self._parse_csv(self._parse_type_size)
5016
5017                # https://docs.snowflake.com/en/sql-reference/data-types-vector
5018                if type_token == TokenType.VECTOR and len(expressions) == 2:
5019                    expressions[0] = exp.DataType.build(expressions[0].name, dialect=self.dialect)
5020
5021            if not expressions or not self._match(TokenType.R_PAREN):
5022                self._retreat(index)
5023                return None
5024
5025            maybe_func = True
5026
5027        values: t.Optional[t.List[exp.Expression]] = None
5028
5029        if nested and self._match(TokenType.LT):
5030            if is_struct:
5031                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
5032            else:
5033                expressions = self._parse_csv(
5034                    lambda: self._parse_types(
5035                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
5036                    )
5037                )
5038
5039            if not self._match(TokenType.GT):
5040                self.raise_error("Expecting >")
5041
5042            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
5043                values = self._parse_csv(self._parse_assignment)
5044                if not values and is_struct:
5045                    values = None
5046                    self._retreat(self._index - 1)
5047                else:
5048                    self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
5049
5050        if type_token in self.TIMESTAMPS:
5051            if self._match_text_seq("WITH", "TIME", "ZONE"):
5052                maybe_func = False
5053                tz_type = (
5054                    exp.DataType.Type.TIMETZ
5055                    if type_token in self.TIMES
5056                    else exp.DataType.Type.TIMESTAMPTZ
5057                )
5058                this = exp.DataType(this=tz_type, expressions=expressions)
5059            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
5060                maybe_func = False
5061                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
5062            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
5063                maybe_func = False
5064        elif type_token == TokenType.INTERVAL:
5065            unit = self._parse_var(upper=True)
5066            if unit:
5067                if self._match_text_seq("TO"):
5068                    unit = exp.IntervalSpan(this=unit, expression=self._parse_var(upper=True))
5069
5070                this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
5071            else:
5072                this = self.expression(exp.DataType, this=exp.DataType.Type.INTERVAL)
5073
5074        if maybe_func and check_func:
5075            index2 = self._index
5076            peek = self._parse_string()
5077
5078            if not peek:
5079                self._retreat(index)
5080                return None
5081
5082            self._retreat(index2)
5083
5084        if not this:
5085            if self._match_text_seq("UNSIGNED"):
5086                unsigned_type_token = self.SIGNED_TO_UNSIGNED_TYPE_TOKEN.get(type_token)
5087                if not unsigned_type_token:
5088                    self.raise_error(f"Cannot convert {type_token.value} to unsigned.")
5089
5090                type_token = unsigned_type_token or type_token
5091
5092            this = exp.DataType(
5093                this=exp.DataType.Type[type_token.value],
5094                expressions=expressions,
5095                nested=nested,
5096                prefix=prefix,
5097            )
5098
5099            # Empty arrays/structs are allowed
5100            if values is not None:
5101                cls = exp.Struct if is_struct else exp.Array
5102                this = exp.cast(cls(expressions=values), this, copy=False)
5103
5104        elif expressions:
5105            this.set("expressions", expressions)
5106
5107        # https://materialize.com/docs/sql/types/list/#type-name
5108        while self._match(TokenType.LIST):
5109            this = exp.DataType(this=exp.DataType.Type.LIST, expressions=[this], nested=True)
5110
5111        index = self._index
5112
5113        # Postgres supports the INT ARRAY[3] syntax as a synonym for INT[3]
5114        matched_array = self._match(TokenType.ARRAY)
5115
5116        while self._curr:
5117            datatype_token = self._prev.token_type
5118            matched_l_bracket = self._match(TokenType.L_BRACKET)
5119            if not matched_l_bracket and not matched_array:
5120                break
5121
5122            matched_array = False
5123            values = self._parse_csv(self._parse_assignment) or None
5124            if (
5125                values
5126                and not schema
5127                and (
5128                    not self.dialect.SUPPORTS_FIXED_SIZE_ARRAYS or datatype_token == TokenType.ARRAY
5129                )
5130            ):
5131                # Retreating here means that we should not parse the following values as part of the data type, e.g. in DuckDB
5132                # 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
5133                self._retreat(index)
5134                break
5135
5136            this = exp.DataType(
5137                this=exp.DataType.Type.ARRAY, expressions=[this], values=values, nested=True
5138            )
5139            self._match(TokenType.R_BRACKET)
5140
5141        if self.TYPE_CONVERTERS and isinstance(this.this, exp.DataType.Type):
5142            converter = self.TYPE_CONVERTERS.get(this.this)
5143            if converter:
5144                this = converter(t.cast(exp.DataType, this))
5145
5146        return this
5147
5148    def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
5149        index = self._index
5150
5151        if (
5152            self._curr
5153            and self._next
5154            and self._curr.token_type in self.TYPE_TOKENS
5155            and self._next.token_type in self.TYPE_TOKENS
5156        ):
5157            # Takes care of special cases like `STRUCT<list ARRAY<...>>` where the identifier is also a
5158            # type token. Without this, the list will be parsed as a type and we'll eventually crash
5159            this = self._parse_id_var()
5160        else:
5161            this = (
5162                self._parse_type(parse_interval=False, fallback_to_identifier=True)
5163                or self._parse_id_var()
5164            )
5165
5166        self._match(TokenType.COLON)
5167
5168        if (
5169            type_required
5170            and not isinstance(this, exp.DataType)
5171            and not self._match_set(self.TYPE_TOKENS, advance=False)
5172        ):
5173            self._retreat(index)
5174            return self._parse_types()
5175
5176        return self._parse_column_def(this)
5177
5178    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5179        if not self._match_text_seq("AT", "TIME", "ZONE"):
5180            return this
5181        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
5182
5183    def _parse_column(self) -> t.Optional[exp.Expression]:
5184        this = self._parse_column_reference()
5185        column = self._parse_column_ops(this) if this else self._parse_bracket(this)
5186
5187        if self.dialect.SUPPORTS_COLUMN_JOIN_MARKS and column:
5188            column.set("join_mark", self._match(TokenType.JOIN_MARKER))
5189
5190        return column
5191
5192    def _parse_column_reference(self) -> t.Optional[exp.Expression]:
5193        this = self._parse_field()
5194        if (
5195            not this
5196            and self._match(TokenType.VALUES, advance=False)
5197            and self.VALUES_FOLLOWED_BY_PAREN
5198            and (not self._next or self._next.token_type != TokenType.L_PAREN)
5199        ):
5200            this = self._parse_id_var()
5201
5202        if isinstance(this, exp.Identifier):
5203            # We bubble up comments from the Identifier to the Column
5204            this = self.expression(exp.Column, comments=this.pop_comments(), this=this)
5205
5206        return this
5207
5208    def _parse_colon_as_variant_extract(
5209        self, this: t.Optional[exp.Expression]
5210    ) -> t.Optional[exp.Expression]:
5211        casts = []
5212        json_path = []
5213        escape = None
5214
5215        while self._match(TokenType.COLON):
5216            start_index = self._index
5217
5218            # Snowflake allows reserved keywords as json keys but advance_any() excludes TokenType.SELECT from any_tokens=True
5219            path = self._parse_column_ops(
5220                self._parse_field(any_token=True, tokens=(TokenType.SELECT,))
5221            )
5222
5223            # The cast :: operator has a lower precedence than the extraction operator :, so
5224            # we rearrange the AST appropriately to avoid casting the JSON path
5225            while isinstance(path, exp.Cast):
5226                casts.append(path.to)
5227                path = path.this
5228
5229            if casts:
5230                dcolon_offset = next(
5231                    i
5232                    for i, t in enumerate(self._tokens[start_index:])
5233                    if t.token_type == TokenType.DCOLON
5234                )
5235                end_token = self._tokens[start_index + dcolon_offset - 1]
5236            else:
5237                end_token = self._prev
5238
5239            if path:
5240                # Escape single quotes from Snowflake's colon extraction (e.g. col:"a'b") as
5241                # it'll roundtrip to a string literal in GET_PATH
5242                if isinstance(path, exp.Identifier) and path.quoted:
5243                    escape = True
5244
5245                json_path.append(self._find_sql(self._tokens[start_index], end_token))
5246
5247        # The VARIANT extract in Snowflake/Databricks is parsed as a JSONExtract; Snowflake uses the json_path in GET_PATH() while
5248        # Databricks transforms it back to the colon/dot notation
5249        if json_path:
5250            json_path_expr = self.dialect.to_json_path(exp.Literal.string(".".join(json_path)))
5251
5252            if json_path_expr:
5253                json_path_expr.set("escape", escape)
5254
5255            this = self.expression(
5256                exp.JSONExtract,
5257                this=this,
5258                expression=json_path_expr,
5259                variant_extract=True,
5260            )
5261
5262            while casts:
5263                this = self.expression(exp.Cast, this=this, to=casts.pop())
5264
5265        return this
5266
5267    def _parse_dcolon(self) -> t.Optional[exp.Expression]:
5268        return self._parse_types()
5269
5270    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5271        this = self._parse_bracket(this)
5272
5273        while self._match_set(self.COLUMN_OPERATORS):
5274            op_token = self._prev.token_type
5275            op = self.COLUMN_OPERATORS.get(op_token)
5276
5277            if op_token == TokenType.DCOLON:
5278                field = self._parse_dcolon()
5279                if not field:
5280                    self.raise_error("Expected type")
5281            elif op and self._curr:
5282                field = self._parse_column_reference() or self._parse_bracket()
5283            else:
5284                field = self._parse_field(any_token=True, anonymous_func=True)
5285
5286            if isinstance(field, (exp.Func, exp.Window)) and this:
5287                # BQ & snowflake allow function calls like x.y.count(...), SAFE.SUBSTR(...) etc
5288                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
5289                this = exp.replace_tree(
5290                    this,
5291                    lambda n: (
5292                        self.expression(exp.Dot, this=n.args.get("table"), expression=n.this)
5293                        if n.table
5294                        else n.this
5295                    )
5296                    if isinstance(n, exp.Column)
5297                    else n,
5298                )
5299
5300            if op:
5301                this = op(self, this, field)
5302            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
5303                this = self.expression(
5304                    exp.Column,
5305                    comments=this.comments,
5306                    this=field,
5307                    table=this.this,
5308                    db=this.args.get("table"),
5309                    catalog=this.args.get("db"),
5310                )
5311            elif isinstance(field, exp.Window):
5312                # Move the exp.Dot's to the window's function
5313                window_func = self.expression(exp.Dot, this=this, expression=field.this)
5314                field.set("this", window_func)
5315                this = field
5316            else:
5317                this = self.expression(exp.Dot, this=this, expression=field)
5318
5319            if field and field.comments:
5320                t.cast(exp.Expression, this).add_comments(field.pop_comments())
5321
5322            this = self._parse_bracket(this)
5323
5324        return self._parse_colon_as_variant_extract(this) if self.COLON_IS_VARIANT_EXTRACT else this
5325
5326    def _parse_primary(self) -> t.Optional[exp.Expression]:
5327        if self._match_set(self.PRIMARY_PARSERS):
5328            token_type = self._prev.token_type
5329            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
5330
5331            if token_type == TokenType.STRING:
5332                expressions = [primary]
5333                while self._match(TokenType.STRING):
5334                    expressions.append(exp.Literal.string(self._prev.text))
5335
5336                if len(expressions) > 1:
5337                    return self.expression(exp.Concat, expressions=expressions)
5338
5339            return primary
5340
5341        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
5342            return exp.Literal.number(f"0.{self._prev.text}")
5343
5344        if self._match(TokenType.L_PAREN):
5345            comments = self._prev_comments
5346            query = self._parse_select()
5347
5348            if query:
5349                expressions = [query]
5350            else:
5351                expressions = self._parse_expressions()
5352
5353            this = self._parse_query_modifiers(seq_get(expressions, 0))
5354
5355            if not this and self._match(TokenType.R_PAREN, advance=False):
5356                this = self.expression(exp.Tuple)
5357            elif isinstance(this, exp.UNWRAPPED_QUERIES):
5358                this = self._parse_subquery(this=this, parse_alias=False)
5359            elif isinstance(this, exp.Subquery):
5360                this = self._parse_subquery(
5361                    this=self._parse_set_operations(this), parse_alias=False
5362                )
5363            elif len(expressions) > 1 or self._prev.token_type == TokenType.COMMA:
5364                this = self.expression(exp.Tuple, expressions=expressions)
5365            else:
5366                this = self.expression(exp.Paren, this=this)
5367
5368            if this:
5369                this.add_comments(comments)
5370
5371            self._match_r_paren(expression=this)
5372            return this
5373
5374        return None
5375
5376    def _parse_field(
5377        self,
5378        any_token: bool = False,
5379        tokens: t.Optional[t.Collection[TokenType]] = None,
5380        anonymous_func: bool = False,
5381    ) -> t.Optional[exp.Expression]:
5382        if anonymous_func:
5383            field = (
5384                self._parse_function(anonymous=anonymous_func, any_token=any_token)
5385                or self._parse_primary()
5386            )
5387        else:
5388            field = self._parse_primary() or self._parse_function(
5389                anonymous=anonymous_func, any_token=any_token
5390            )
5391        return field or self._parse_id_var(any_token=any_token, tokens=tokens)
5392
5393    def _parse_function(
5394        self,
5395        functions: t.Optional[t.Dict[str, t.Callable]] = None,
5396        anonymous: bool = False,
5397        optional_parens: bool = True,
5398        any_token: bool = False,
5399    ) -> t.Optional[exp.Expression]:
5400        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
5401        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
5402        fn_syntax = False
5403        if (
5404            self._match(TokenType.L_BRACE, advance=False)
5405            and self._next
5406            and self._next.text.upper() == "FN"
5407        ):
5408            self._advance(2)
5409            fn_syntax = True
5410
5411        func = self._parse_function_call(
5412            functions=functions,
5413            anonymous=anonymous,
5414            optional_parens=optional_parens,
5415            any_token=any_token,
5416        )
5417
5418        if fn_syntax:
5419            self._match(TokenType.R_BRACE)
5420
5421        return func
5422
5423    def _parse_function_call(
5424        self,
5425        functions: t.Optional[t.Dict[str, t.Callable]] = None,
5426        anonymous: bool = False,
5427        optional_parens: bool = True,
5428        any_token: bool = False,
5429    ) -> t.Optional[exp.Expression]:
5430        if not self._curr:
5431            return None
5432
5433        comments = self._curr.comments
5434        token_type = self._curr.token_type
5435        this = self._curr.text
5436        upper = this.upper()
5437
5438        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
5439        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
5440            self._advance()
5441            return self._parse_window(parser(self))
5442
5443        if not self._next or self._next.token_type != TokenType.L_PAREN:
5444            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
5445                self._advance()
5446                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
5447
5448            return None
5449
5450        if any_token:
5451            if token_type in self.RESERVED_TOKENS:
5452                return None
5453        elif token_type not in self.FUNC_TOKENS:
5454            return None
5455
5456        self._advance(2)
5457
5458        parser = self.FUNCTION_PARSERS.get(upper)
5459        if parser and not anonymous:
5460            this = parser(self)
5461        else:
5462            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
5463
5464            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
5465                this = self.expression(
5466                    subquery_predicate, comments=comments, this=self._parse_select()
5467                )
5468                self._match_r_paren()
5469                return this
5470
5471            if functions is None:
5472                functions = self.FUNCTIONS
5473
5474            function = functions.get(upper)
5475            known_function = function and not anonymous
5476
5477            alias = not known_function or upper in self.FUNCTIONS_WITH_ALIASED_ARGS
5478            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
5479
5480            post_func_comments = self._curr and self._curr.comments
5481            if known_function and post_func_comments:
5482                # If the user-inputted comment "/* sqlglot.anonymous */" is following the function
5483                # call we'll construct it as exp.Anonymous, even if it's "known"
5484                if any(
5485                    comment.lstrip().startswith(exp.SQLGLOT_ANONYMOUS)
5486                    for comment in post_func_comments
5487                ):
5488                    known_function = False
5489
5490            if alias and known_function:
5491                args = self._kv_to_prop_eq(args)
5492
5493            if known_function:
5494                func_builder = t.cast(t.Callable, function)
5495
5496                if "dialect" in func_builder.__code__.co_varnames:
5497                    func = func_builder(args, dialect=self.dialect)
5498                else:
5499                    func = func_builder(args)
5500
5501                func = self.validate_expression(func, args)
5502                if self.dialect.PRESERVE_ORIGINAL_NAMES:
5503                    func.meta["name"] = this
5504
5505                this = func
5506            else:
5507                if token_type == TokenType.IDENTIFIER:
5508                    this = exp.Identifier(this=this, quoted=True)
5509                this = self.expression(exp.Anonymous, this=this, expressions=args)
5510
5511        if isinstance(this, exp.Expression):
5512            this.add_comments(comments)
5513
5514        self._match_r_paren(this)
5515        return self._parse_window(this)
5516
5517    def _to_prop_eq(self, expression: exp.Expression, index: int) -> exp.Expression:
5518        return expression
5519
5520    def _kv_to_prop_eq(self, expressions: t.List[exp.Expression]) -> t.List[exp.Expression]:
5521        transformed = []
5522
5523        for index, e in enumerate(expressions):
5524            if isinstance(e, self.KEY_VALUE_DEFINITIONS):
5525                if isinstance(e, exp.Alias):
5526                    e = self.expression(exp.PropertyEQ, this=e.args.get("alias"), expression=e.this)
5527
5528                if not isinstance(e, exp.PropertyEQ):
5529                    e = self.expression(
5530                        exp.PropertyEQ, this=exp.to_identifier(e.this.name), expression=e.expression
5531                    )
5532
5533                if isinstance(e.this, exp.Column):
5534                    e.this.replace(e.this.this)
5535            else:
5536                e = self._to_prop_eq(e, index)
5537
5538            transformed.append(e)
5539
5540        return transformed
5541
5542    def _parse_user_defined_function_expression(self) -> t.Optional[exp.Expression]:
5543        return self._parse_statement()
5544
5545    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
5546        return self._parse_column_def(self._parse_id_var())
5547
5548    def _parse_user_defined_function(
5549        self, kind: t.Optional[TokenType] = None
5550    ) -> t.Optional[exp.Expression]:
5551        this = self._parse_id_var()
5552
5553        while self._match(TokenType.DOT):
5554            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
5555
5556        if not self._match(TokenType.L_PAREN):
5557            return this
5558
5559        expressions = self._parse_csv(self._parse_function_parameter)
5560        self._match_r_paren()
5561        return self.expression(
5562            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
5563        )
5564
5565    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
5566        literal = self._parse_primary()
5567        if literal:
5568            return self.expression(exp.Introducer, this=token.text, expression=literal)
5569
5570        return self.expression(exp.Identifier, this=token.text)
5571
5572    def _parse_session_parameter(self) -> exp.SessionParameter:
5573        kind = None
5574        this = self._parse_id_var() or self._parse_primary()
5575
5576        if this and self._match(TokenType.DOT):
5577            kind = this.name
5578            this = self._parse_var() or self._parse_primary()
5579
5580        return self.expression(exp.SessionParameter, this=this, kind=kind)
5581
5582    def _parse_lambda_arg(self) -> t.Optional[exp.Expression]:
5583        return self._parse_id_var()
5584
5585    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
5586        index = self._index
5587
5588        if self._match(TokenType.L_PAREN):
5589            expressions = t.cast(
5590                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_lambda_arg)
5591            )
5592
5593            if not self._match(TokenType.R_PAREN):
5594                self._retreat(index)
5595        else:
5596            expressions = [self._parse_lambda_arg()]
5597
5598        if self._match_set(self.LAMBDAS):
5599            return self.LAMBDAS[self._prev.token_type](self, expressions)
5600
5601        self._retreat(index)
5602
5603        this: t.Optional[exp.Expression]
5604
5605        if self._match(TokenType.DISTINCT):
5606            this = self.expression(
5607                exp.Distinct, expressions=self._parse_csv(self._parse_assignment)
5608            )
5609        else:
5610            this = self._parse_select_or_expression(alias=alias)
5611
5612        return self._parse_limit(
5613            self._parse_order(self._parse_having_max(self._parse_respect_or_ignore_nulls(this)))
5614        )
5615
5616    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
5617        index = self._index
5618        if not self._match(TokenType.L_PAREN):
5619            return this
5620
5621        # Disambiguate between schema and subquery/CTE, e.g. in INSERT INTO table (<expr>),
5622        # expr can be of both types
5623        if self._match_set(self.SELECT_START_TOKENS):
5624            self._retreat(index)
5625            return this
5626        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
5627        self._match_r_paren()
5628        return self.expression(exp.Schema, this=this, expressions=args)
5629
5630    def _parse_field_def(self) -> t.Optional[exp.Expression]:
5631        return self._parse_column_def(self._parse_field(any_token=True))
5632
5633    def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5634        # column defs are not really columns, they're identifiers
5635        if isinstance(this, exp.Column):
5636            this = this.this
5637
5638        kind = self._parse_types(schema=True)
5639
5640        if self._match_text_seq("FOR", "ORDINALITY"):
5641            return self.expression(exp.ColumnDef, this=this, ordinality=True)
5642
5643        constraints: t.List[exp.Expression] = []
5644
5645        if (not kind and self._match(TokenType.ALIAS)) or self._match_texts(
5646            ("ALIAS", "MATERIALIZED")
5647        ):
5648            persisted = self._prev.text.upper() == "MATERIALIZED"
5649            constraint_kind = exp.ComputedColumnConstraint(
5650                this=self._parse_assignment(),
5651                persisted=persisted or self._match_text_seq("PERSISTED"),
5652                not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
5653            )
5654            constraints.append(self.expression(exp.ColumnConstraint, kind=constraint_kind))
5655        elif (
5656            kind
5657            and self._match(TokenType.ALIAS, advance=False)
5658            and (
5659                not self.WRAPPED_TRANSFORM_COLUMN_CONSTRAINT
5660                or (self._next and self._next.token_type == TokenType.L_PAREN)
5661            )
5662        ):
5663            self._advance()
5664            constraints.append(
5665                self.expression(
5666                    exp.ColumnConstraint,
5667                    kind=exp.TransformColumnConstraint(this=self._parse_disjunction()),
5668                )
5669            )
5670
5671        while True:
5672            constraint = self._parse_column_constraint()
5673            if not constraint:
5674                break
5675            constraints.append(constraint)
5676
5677        if not kind and not constraints:
5678            return this
5679
5680        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
5681
5682    def _parse_auto_increment(
5683        self,
5684    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
5685        start = None
5686        increment = None
5687
5688        if self._match(TokenType.L_PAREN, advance=False):
5689            args = self._parse_wrapped_csv(self._parse_bitwise)
5690            start = seq_get(args, 0)
5691            increment = seq_get(args, 1)
5692        elif self._match_text_seq("START"):
5693            start = self._parse_bitwise()
5694            self._match_text_seq("INCREMENT")
5695            increment = self._parse_bitwise()
5696
5697        if start and increment:
5698            return exp.GeneratedAsIdentityColumnConstraint(start=start, increment=increment)
5699
5700        return exp.AutoIncrementColumnConstraint()
5701
5702    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
5703        if not self._match_text_seq("REFRESH"):
5704            self._retreat(self._index - 1)
5705            return None
5706        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
5707
5708    def _parse_compress(self) -> exp.CompressColumnConstraint:
5709        if self._match(TokenType.L_PAREN, advance=False):
5710            return self.expression(
5711                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
5712            )
5713
5714        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
5715
5716    def _parse_generated_as_identity(
5717        self,
5718    ) -> (
5719        exp.GeneratedAsIdentityColumnConstraint
5720        | exp.ComputedColumnConstraint
5721        | exp.GeneratedAsRowColumnConstraint
5722    ):
5723        if self._match_text_seq("BY", "DEFAULT"):
5724            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
5725            this = self.expression(
5726                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
5727            )
5728        else:
5729            self._match_text_seq("ALWAYS")
5730            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
5731
5732        self._match(TokenType.ALIAS)
5733
5734        if self._match_text_seq("ROW"):
5735            start = self._match_text_seq("START")
5736            if not start:
5737                self._match(TokenType.END)
5738            hidden = self._match_text_seq("HIDDEN")
5739            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
5740
5741        identity = self._match_text_seq("IDENTITY")
5742
5743        if self._match(TokenType.L_PAREN):
5744            if self._match(TokenType.START_WITH):
5745                this.set("start", self._parse_bitwise())
5746            if self._match_text_seq("INCREMENT", "BY"):
5747                this.set("increment", self._parse_bitwise())
5748            if self._match_text_seq("MINVALUE"):
5749                this.set("minvalue", self._parse_bitwise())
5750            if self._match_text_seq("MAXVALUE"):
5751                this.set("maxvalue", self._parse_bitwise())
5752
5753            if self._match_text_seq("CYCLE"):
5754                this.set("cycle", True)
5755            elif self._match_text_seq("NO", "CYCLE"):
5756                this.set("cycle", False)
5757
5758            if not identity:
5759                this.set("expression", self._parse_range())
5760            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
5761                args = self._parse_csv(self._parse_bitwise)
5762                this.set("start", seq_get(args, 0))
5763                this.set("increment", seq_get(args, 1))
5764
5765            self._match_r_paren()
5766
5767        return this
5768
5769    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
5770        self._match_text_seq("LENGTH")
5771        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
5772
5773    def _parse_not_constraint(self) -> t.Optional[exp.Expression]:
5774        if self._match_text_seq("NULL"):
5775            return self.expression(exp.NotNullColumnConstraint)
5776        if self._match_text_seq("CASESPECIFIC"):
5777            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
5778        if self._match_text_seq("FOR", "REPLICATION"):
5779            return self.expression(exp.NotForReplicationColumnConstraint)
5780
5781        # Unconsume the `NOT` token
5782        self._retreat(self._index - 1)
5783        return None
5784
5785    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
5786        this = self._match(TokenType.CONSTRAINT) and self._parse_id_var()
5787
5788        procedure_option_follows = (
5789            self._match(TokenType.WITH, advance=False)
5790            and self._next
5791            and self._next.text.upper() in self.PROCEDURE_OPTIONS
5792        )
5793
5794        if not procedure_option_follows and self._match_texts(self.CONSTRAINT_PARSERS):
5795            return self.expression(
5796                exp.ColumnConstraint,
5797                this=this,
5798                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
5799            )
5800
5801        return this
5802
5803    def _parse_constraint(self) -> t.Optional[exp.Expression]:
5804        if not self._match(TokenType.CONSTRAINT):
5805            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
5806
5807        return self.expression(
5808            exp.Constraint,
5809            this=self._parse_id_var(),
5810            expressions=self._parse_unnamed_constraints(),
5811        )
5812
5813    def _parse_unnamed_constraints(self) -> t.List[exp.Expression]:
5814        constraints = []
5815        while True:
5816            constraint = self._parse_unnamed_constraint() or self._parse_function()
5817            if not constraint:
5818                break
5819            constraints.append(constraint)
5820
5821        return constraints
5822
5823    def _parse_unnamed_constraint(
5824        self, constraints: t.Optional[t.Collection[str]] = None
5825    ) -> t.Optional[exp.Expression]:
5826        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
5827            constraints or self.CONSTRAINT_PARSERS
5828        ):
5829            return None
5830
5831        constraint = self._prev.text.upper()
5832        if constraint not in self.CONSTRAINT_PARSERS:
5833            self.raise_error(f"No parser found for schema constraint {constraint}.")
5834
5835        return self.CONSTRAINT_PARSERS[constraint](self)
5836
5837    def _parse_unique_key(self) -> t.Optional[exp.Expression]:
5838        return self._parse_id_var(any_token=False)
5839
5840    def _parse_unique(self) -> exp.UniqueColumnConstraint:
5841        self._match_text_seq("KEY")
5842        return self.expression(
5843            exp.UniqueColumnConstraint,
5844            nulls=self._match_text_seq("NULLS", "NOT", "DISTINCT"),
5845            this=self._parse_schema(self._parse_unique_key()),
5846            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
5847            on_conflict=self._parse_on_conflict(),
5848        )
5849
5850    def _parse_key_constraint_options(self) -> t.List[str]:
5851        options = []
5852        while True:
5853            if not self._curr:
5854                break
5855
5856            if self._match(TokenType.ON):
5857                action = None
5858                on = self._advance_any() and self._prev.text
5859
5860                if self._match_text_seq("NO", "ACTION"):
5861                    action = "NO ACTION"
5862                elif self._match_text_seq("CASCADE"):
5863                    action = "CASCADE"
5864                elif self._match_text_seq("RESTRICT"):
5865                    action = "RESTRICT"
5866                elif self._match_pair(TokenType.SET, TokenType.NULL):
5867                    action = "SET NULL"
5868                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
5869                    action = "SET DEFAULT"
5870                else:
5871                    self.raise_error("Invalid key constraint")
5872
5873                options.append(f"ON {on} {action}")
5874            else:
5875                var = self._parse_var_from_options(
5876                    self.KEY_CONSTRAINT_OPTIONS, raise_unmatched=False
5877                )
5878                if not var:
5879                    break
5880                options.append(var.name)
5881
5882        return options
5883
5884    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
5885        if match and not self._match(TokenType.REFERENCES):
5886            return None
5887
5888        expressions = None
5889        this = self._parse_table(schema=True)
5890        options = self._parse_key_constraint_options()
5891        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
5892
5893    def _parse_foreign_key(self) -> exp.ForeignKey:
5894        expressions = self._parse_wrapped_id_vars()
5895        reference = self._parse_references()
5896        options = {}
5897
5898        while self._match(TokenType.ON):
5899            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
5900                self.raise_error("Expected DELETE or UPDATE")
5901
5902            kind = self._prev.text.lower()
5903
5904            if self._match_text_seq("NO", "ACTION"):
5905                action = "NO ACTION"
5906            elif self._match(TokenType.SET):
5907                self._match_set((TokenType.NULL, TokenType.DEFAULT))
5908                action = "SET " + self._prev.text.upper()
5909            else:
5910                self._advance()
5911                action = self._prev.text.upper()
5912
5913            options[kind] = action
5914
5915        return self.expression(
5916            exp.ForeignKey,
5917            expressions=expressions,
5918            reference=reference,
5919            **options,  # type: ignore
5920        )
5921
5922    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
5923        return self._parse_ordered() or self._parse_field()
5924
5925    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
5926        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
5927            self._retreat(self._index - 1)
5928            return None
5929
5930        id_vars = self._parse_wrapped_id_vars()
5931        return self.expression(
5932            exp.PeriodForSystemTimeConstraint,
5933            this=seq_get(id_vars, 0),
5934            expression=seq_get(id_vars, 1),
5935        )
5936
5937    def _parse_primary_key(
5938        self, wrapped_optional: bool = False, in_props: bool = False
5939    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
5940        desc = (
5941            self._match_set((TokenType.ASC, TokenType.DESC))
5942            and self._prev.token_type == TokenType.DESC
5943        )
5944
5945        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
5946            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
5947
5948        expressions = self._parse_wrapped_csv(
5949            self._parse_primary_key_part, optional=wrapped_optional
5950        )
5951        options = self._parse_key_constraint_options()
5952        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
5953
5954    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
5955        return self._parse_slice(self._parse_alias(self._parse_assignment(), explicit=True))
5956
5957    def _parse_odbc_datetime_literal(self) -> exp.Expression:
5958        """
5959        Parses a datetime column in ODBC format. We parse the column into the corresponding
5960        types, for example `{d'yyyy-mm-dd'}` will be parsed as a `Date` column, exactly the
5961        same as we did for `DATE('yyyy-mm-dd')`.
5962
5963        Reference:
5964        https://learn.microsoft.com/en-us/sql/odbc/reference/develop-app/date-time-and-timestamp-literals
5965        """
5966        self._match(TokenType.VAR)
5967        exp_class = self.ODBC_DATETIME_LITERALS[self._prev.text.lower()]
5968        expression = self.expression(exp_class=exp_class, this=self._parse_string())
5969        if not self._match(TokenType.R_BRACE):
5970            self.raise_error("Expected }")
5971        return expression
5972
5973    def _parse_bracket(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
5974        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
5975            return this
5976
5977        bracket_kind = self._prev.token_type
5978        if (
5979            bracket_kind == TokenType.L_BRACE
5980            and self._curr
5981            and self._curr.token_type == TokenType.VAR
5982            and self._curr.text.lower() in self.ODBC_DATETIME_LITERALS
5983        ):
5984            return self._parse_odbc_datetime_literal()
5985
5986        expressions = self._parse_csv(
5987            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
5988        )
5989
5990        if bracket_kind == TokenType.L_BRACKET and not self._match(TokenType.R_BRACKET):
5991            self.raise_error("Expected ]")
5992        elif bracket_kind == TokenType.L_BRACE and not self._match(TokenType.R_BRACE):
5993            self.raise_error("Expected }")
5994
5995        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
5996        if bracket_kind == TokenType.L_BRACE:
5997            this = self.expression(exp.Struct, expressions=self._kv_to_prop_eq(expressions))
5998        elif not this:
5999            this = build_array_constructor(
6000                exp.Array, args=expressions, bracket_kind=bracket_kind, dialect=self.dialect
6001            )
6002        else:
6003            constructor_type = self.ARRAY_CONSTRUCTORS.get(this.name.upper())
6004            if constructor_type:
6005                return build_array_constructor(
6006                    constructor_type,
6007                    args=expressions,
6008                    bracket_kind=bracket_kind,
6009                    dialect=self.dialect,
6010                )
6011
6012            expressions = apply_index_offset(this, expressions, -self.dialect.INDEX_OFFSET)
6013            this = self.expression(exp.Bracket, this=this, expressions=expressions)
6014
6015        self._add_comments(this)
6016        return self._parse_bracket(this)
6017
6018    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
6019        if self._match(TokenType.COLON):
6020            return self.expression(exp.Slice, this=this, expression=self._parse_assignment())
6021        return this
6022
6023    def _parse_case(self) -> t.Optional[exp.Expression]:
6024        ifs = []
6025        default = None
6026
6027        comments = self._prev_comments
6028        expression = self._parse_assignment()
6029
6030        while self._match(TokenType.WHEN):
6031            this = self._parse_assignment()
6032            self._match(TokenType.THEN)
6033            then = self._parse_assignment()
6034            ifs.append(self.expression(exp.If, this=this, true=then))
6035
6036        if self._match(TokenType.ELSE):
6037            default = self._parse_assignment()
6038
6039        if not self._match(TokenType.END):
6040            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
6041                default = exp.column("interval")
6042            else:
6043                self.raise_error("Expected END after CASE", self._prev)
6044
6045        return self.expression(
6046            exp.Case, comments=comments, this=expression, ifs=ifs, default=default
6047        )
6048
6049    def _parse_if(self) -> t.Optional[exp.Expression]:
6050        if self._match(TokenType.L_PAREN):
6051            args = self._parse_csv(self._parse_assignment)
6052            this = self.validate_expression(exp.If.from_arg_list(args), args)
6053            self._match_r_paren()
6054        else:
6055            index = self._index - 1
6056
6057            if self.NO_PAREN_IF_COMMANDS and index == 0:
6058                return self._parse_as_command(self._prev)
6059
6060            condition = self._parse_assignment()
6061
6062            if not condition:
6063                self._retreat(index)
6064                return None
6065
6066            self._match(TokenType.THEN)
6067            true = self._parse_assignment()
6068            false = self._parse_assignment() if self._match(TokenType.ELSE) else None
6069            self._match(TokenType.END)
6070            this = self.expression(exp.If, this=condition, true=true, false=false)
6071
6072        return this
6073
6074    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
6075        if not self._match_text_seq("VALUE", "FOR"):
6076            self._retreat(self._index - 1)
6077            return None
6078
6079        return self.expression(
6080            exp.NextValueFor,
6081            this=self._parse_column(),
6082            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
6083        )
6084
6085    def _parse_extract(self) -> exp.Extract | exp.Anonymous:
6086        this = self._parse_function() or self._parse_var_or_string(upper=True)
6087
6088        if self._match(TokenType.FROM):
6089            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
6090
6091        if not self._match(TokenType.COMMA):
6092            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
6093
6094        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
6095
6096    def _parse_gap_fill(self) -> exp.GapFill:
6097        self._match(TokenType.TABLE)
6098        this = self._parse_table()
6099
6100        self._match(TokenType.COMMA)
6101        args = [this, *self._parse_csv(self._parse_lambda)]
6102
6103        gap_fill = exp.GapFill.from_arg_list(args)
6104        return self.validate_expression(gap_fill, args)
6105
6106    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
6107        this = self._parse_assignment()
6108
6109        if not self._match(TokenType.ALIAS):
6110            if self._match(TokenType.COMMA):
6111                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
6112
6113            self.raise_error("Expected AS after CAST")
6114
6115        fmt = None
6116        to = self._parse_types()
6117
6118        if self._match(TokenType.FORMAT):
6119            fmt_string = self._parse_string()
6120            fmt = self._parse_at_time_zone(fmt_string)
6121
6122            if not to:
6123                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
6124            if to.this in exp.DataType.TEMPORAL_TYPES:
6125                this = self.expression(
6126                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
6127                    this=this,
6128                    format=exp.Literal.string(
6129                        format_time(
6130                            fmt_string.this if fmt_string else "",
6131                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
6132                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
6133                        )
6134                    ),
6135                    safe=safe,
6136                )
6137
6138                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
6139                    this.set("zone", fmt.args["zone"])
6140                return this
6141        elif not to:
6142            self.raise_error("Expected TYPE after CAST")
6143        elif isinstance(to, exp.Identifier):
6144            to = exp.DataType.build(to.name, udt=True)
6145        elif to.this == exp.DataType.Type.CHAR:
6146            if self._match(TokenType.CHARACTER_SET):
6147                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
6148
6149        return self.expression(
6150            exp.Cast if strict else exp.TryCast,
6151            this=this,
6152            to=to,
6153            format=fmt,
6154            safe=safe,
6155            action=self._parse_var_from_options(self.CAST_ACTIONS, raise_unmatched=False),
6156        )
6157
6158    def _parse_string_agg(self) -> exp.GroupConcat:
6159        if self._match(TokenType.DISTINCT):
6160            args: t.List[t.Optional[exp.Expression]] = [
6161                self.expression(exp.Distinct, expressions=[self._parse_assignment()])
6162            ]
6163            if self._match(TokenType.COMMA):
6164                args.extend(self._parse_csv(self._parse_assignment))
6165        else:
6166            args = self._parse_csv(self._parse_assignment)  # type: ignore
6167
6168        if self._match_text_seq("ON", "OVERFLOW"):
6169            # trino: LISTAGG(expression [, separator] [ON OVERFLOW overflow_behavior])
6170            if self._match_text_seq("ERROR"):
6171                on_overflow: t.Optional[exp.Expression] = exp.var("ERROR")
6172            else:
6173                self._match_text_seq("TRUNCATE")
6174                on_overflow = self.expression(
6175                    exp.OverflowTruncateBehavior,
6176                    this=self._parse_string(),
6177                    with_count=(
6178                        self._match_text_seq("WITH", "COUNT")
6179                        or not self._match_text_seq("WITHOUT", "COUNT")
6180                    ),
6181                )
6182        else:
6183            on_overflow = None
6184
6185        index = self._index
6186        if not self._match(TokenType.R_PAREN) and args:
6187            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
6188            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
6189            args[-1] = self._parse_limit(this=self._parse_order(this=args[-1]))
6190            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
6191
6192        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
6193        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
6194        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
6195        if not self._match_text_seq("WITHIN", "GROUP"):
6196            self._retreat(index)
6197            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
6198
6199        # The corresponding match_r_paren will be called in parse_function (caller)
6200        self._match_l_paren()
6201
6202        return self.expression(
6203            exp.GroupConcat,
6204            this=self._parse_order(this=seq_get(args, 0)),
6205            separator=seq_get(args, 1),
6206            on_overflow=on_overflow,
6207        )
6208
6209    def _parse_convert(
6210        self, strict: bool, safe: t.Optional[bool] = None
6211    ) -> t.Optional[exp.Expression]:
6212        this = self._parse_bitwise()
6213
6214        if self._match(TokenType.USING):
6215            to: t.Optional[exp.Expression] = self.expression(
6216                exp.CharacterSet, this=self._parse_var()
6217            )
6218        elif self._match(TokenType.COMMA):
6219            to = self._parse_types()
6220        else:
6221            to = None
6222
6223        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
6224
6225    def _parse_xml_table(self) -> exp.XMLTable:
6226        namespaces = None
6227        passing = None
6228        columns = None
6229
6230        if self._match_text_seq("XMLNAMESPACES", "("):
6231            namespaces = self._parse_xml_namespace()
6232            self._match_text_seq(")", ",")
6233
6234        this = self._parse_string()
6235
6236        if self._match_text_seq("PASSING"):
6237            # The BY VALUE keywords are optional and are provided for semantic clarity
6238            self._match_text_seq("BY", "VALUE")
6239            passing = self._parse_csv(self._parse_column)
6240
6241        by_ref = self._match_text_seq("RETURNING", "SEQUENCE", "BY", "REF")
6242
6243        if self._match_text_seq("COLUMNS"):
6244            columns = self._parse_csv(self._parse_field_def)
6245
6246        return self.expression(
6247            exp.XMLTable,
6248            this=this,
6249            namespaces=namespaces,
6250            passing=passing,
6251            columns=columns,
6252            by_ref=by_ref,
6253        )
6254
6255    def _parse_xml_namespace(self) -> t.List[exp.XMLNamespace]:
6256        namespaces = []
6257
6258        while True:
6259            if self._match_text_seq("DEFAULT"):
6260                uri = self._parse_string()
6261            else:
6262                uri = self._parse_alias(self._parse_string())
6263            namespaces.append(self.expression(exp.XMLNamespace, this=uri))
6264            if not self._match(TokenType.COMMA):
6265                break
6266
6267        return namespaces
6268
6269    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
6270        """
6271        There are generally two variants of the DECODE function:
6272
6273        - DECODE(bin, charset)
6274        - DECODE(expression, search, result [, search, result] ... [, default])
6275
6276        The second variant will always be parsed into a CASE expression. Note that NULL
6277        needs special treatment, since we need to explicitly check for it with `IS NULL`,
6278        instead of relying on pattern matching.
6279        """
6280        args = self._parse_csv(self._parse_assignment)
6281
6282        if len(args) < 3:
6283            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
6284
6285        expression, *expressions = args
6286        if not expression:
6287            return None
6288
6289        ifs = []
6290        for search, result in zip(expressions[::2], expressions[1::2]):
6291            if not search or not result:
6292                return None
6293
6294            if isinstance(search, exp.Literal):
6295                ifs.append(
6296                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
6297                )
6298            elif isinstance(search, exp.Null):
6299                ifs.append(
6300                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
6301                )
6302            else:
6303                cond = exp.or_(
6304                    exp.EQ(this=expression.copy(), expression=search),
6305                    exp.and_(
6306                        exp.Is(this=expression.copy(), expression=exp.Null()),
6307                        exp.Is(this=search.copy(), expression=exp.Null()),
6308                        copy=False,
6309                    ),
6310                    copy=False,
6311                )
6312                ifs.append(exp.If(this=cond, true=result))
6313
6314        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
6315
6316    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
6317        self._match_text_seq("KEY")
6318        key = self._parse_column()
6319        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
6320        self._match_text_seq("VALUE")
6321        value = self._parse_bitwise()
6322
6323        if not key and not value:
6324            return None
6325        return self.expression(exp.JSONKeyValue, this=key, expression=value)
6326
6327    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
6328        if not this or not self._match_text_seq("FORMAT", "JSON"):
6329            return this
6330
6331        return self.expression(exp.FormatJson, this=this)
6332
6333    def _parse_on_condition(self) -> t.Optional[exp.OnCondition]:
6334        # MySQL uses "X ON EMPTY Y ON ERROR" (e.g. JSON_VALUE) while Oracle uses the opposite (e.g. JSON_EXISTS)
6335        if self.dialect.ON_CONDITION_EMPTY_BEFORE_ERROR:
6336            empty = self._parse_on_handling("EMPTY", *self.ON_CONDITION_TOKENS)
6337            error = self._parse_on_handling("ERROR", *self.ON_CONDITION_TOKENS)
6338        else:
6339            error = self._parse_on_handling("ERROR", *self.ON_CONDITION_TOKENS)
6340            empty = self._parse_on_handling("EMPTY", *self.ON_CONDITION_TOKENS)
6341
6342        null = self._parse_on_handling("NULL", *self.ON_CONDITION_TOKENS)
6343
6344        if not empty and not error and not null:
6345            return None
6346
6347        return self.expression(
6348            exp.OnCondition,
6349            empty=empty,
6350            error=error,
6351            null=null,
6352        )
6353
6354    def _parse_on_handling(
6355        self, on: str, *values: str
6356    ) -> t.Optional[str] | t.Optional[exp.Expression]:
6357        # Parses the "X ON Y" or "DEFAULT <expr> ON Y syntax, e.g. NULL ON NULL (Oracle, T-SQL, MySQL)
6358        for value in values:
6359            if self._match_text_seq(value, "ON", on):
6360                return f"{value} ON {on}"
6361
6362        index = self._index
6363        if self._match(TokenType.DEFAULT):
6364            default_value = self._parse_bitwise()
6365            if self._match_text_seq("ON", on):
6366                return default_value
6367
6368            self._retreat(index)
6369
6370        return None
6371
6372    @t.overload
6373    def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
6374
6375    @t.overload
6376    def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
6377
6378    def _parse_json_object(self, agg=False):
6379        star = self._parse_star()
6380        expressions = (
6381            [star]
6382            if star
6383            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
6384        )
6385        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
6386
6387        unique_keys = None
6388        if self._match_text_seq("WITH", "UNIQUE"):
6389            unique_keys = True
6390        elif self._match_text_seq("WITHOUT", "UNIQUE"):
6391            unique_keys = False
6392
6393        self._match_text_seq("KEYS")
6394
6395        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
6396            self._parse_type()
6397        )
6398        encoding = self._match_text_seq("ENCODING") and self._parse_var()
6399
6400        return self.expression(
6401            exp.JSONObjectAgg if agg else exp.JSONObject,
6402            expressions=expressions,
6403            null_handling=null_handling,
6404            unique_keys=unique_keys,
6405            return_type=return_type,
6406            encoding=encoding,
6407        )
6408
6409    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
6410    def _parse_json_column_def(self) -> exp.JSONColumnDef:
6411        if not self._match_text_seq("NESTED"):
6412            this = self._parse_id_var()
6413            kind = self._parse_types(allow_identifiers=False)
6414            nested = None
6415        else:
6416            this = None
6417            kind = None
6418            nested = True
6419
6420        path = self._match_text_seq("PATH") and self._parse_string()
6421        nested_schema = nested and self._parse_json_schema()
6422
6423        return self.expression(
6424            exp.JSONColumnDef,
6425            this=this,
6426            kind=kind,
6427            path=path,
6428            nested_schema=nested_schema,
6429        )
6430
6431    def _parse_json_schema(self) -> exp.JSONSchema:
6432        self._match_text_seq("COLUMNS")
6433        return self.expression(
6434            exp.JSONSchema,
6435            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
6436        )
6437
6438    def _parse_json_table(self) -> exp.JSONTable:
6439        this = self._parse_format_json(self._parse_bitwise())
6440        path = self._match(TokenType.COMMA) and self._parse_string()
6441        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
6442        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
6443        schema = self._parse_json_schema()
6444
6445        return exp.JSONTable(
6446            this=this,
6447            schema=schema,
6448            path=path,
6449            error_handling=error_handling,
6450            empty_handling=empty_handling,
6451        )
6452
6453    def _parse_match_against(self) -> exp.MatchAgainst:
6454        expressions = self._parse_csv(self._parse_column)
6455
6456        self._match_text_seq(")", "AGAINST", "(")
6457
6458        this = self._parse_string()
6459
6460        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
6461            modifier = "IN NATURAL LANGUAGE MODE"
6462            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
6463                modifier = f"{modifier} WITH QUERY EXPANSION"
6464        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
6465            modifier = "IN BOOLEAN MODE"
6466        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
6467            modifier = "WITH QUERY EXPANSION"
6468        else:
6469            modifier = None
6470
6471        return self.expression(
6472            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
6473        )
6474
6475    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
6476    def _parse_open_json(self) -> exp.OpenJSON:
6477        this = self._parse_bitwise()
6478        path = self._match(TokenType.COMMA) and self._parse_string()
6479
6480        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
6481            this = self._parse_field(any_token=True)
6482            kind = self._parse_types()
6483            path = self._parse_string()
6484            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
6485
6486            return self.expression(
6487                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
6488            )
6489
6490        expressions = None
6491        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
6492            self._match_l_paren()
6493            expressions = self._parse_csv(_parse_open_json_column_def)
6494
6495        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
6496
6497    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
6498        args = self._parse_csv(self._parse_bitwise)
6499
6500        if self._match(TokenType.IN):
6501            return self.expression(
6502                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
6503            )
6504
6505        if haystack_first:
6506            haystack = seq_get(args, 0)
6507            needle = seq_get(args, 1)
6508        else:
6509            haystack = seq_get(args, 1)
6510            needle = seq_get(args, 0)
6511
6512        return self.expression(
6513            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
6514        )
6515
6516    def _parse_predict(self) -> exp.Predict:
6517        self._match_text_seq("MODEL")
6518        this = self._parse_table()
6519
6520        self._match(TokenType.COMMA)
6521        self._match_text_seq("TABLE")
6522
6523        return self.expression(
6524            exp.Predict,
6525            this=this,
6526            expression=self._parse_table(),
6527            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
6528        )
6529
6530    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
6531        args = self._parse_csv(self._parse_table)
6532        return exp.JoinHint(this=func_name.upper(), expressions=args)
6533
6534    def _parse_substring(self) -> exp.Substring:
6535        # Postgres supports the form: substring(string [from int] [for int])
6536        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
6537
6538        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
6539
6540        if self._match(TokenType.FROM):
6541            args.append(self._parse_bitwise())
6542        if self._match(TokenType.FOR):
6543            if len(args) == 1:
6544                args.append(exp.Literal.number(1))
6545            args.append(self._parse_bitwise())
6546
6547        return self.validate_expression(exp.Substring.from_arg_list(args), args)
6548
6549    def _parse_trim(self) -> exp.Trim:
6550        # https://www.w3resource.com/sql/character-functions/trim.php
6551        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
6552
6553        position = None
6554        collation = None
6555        expression = None
6556
6557        if self._match_texts(self.TRIM_TYPES):
6558            position = self._prev.text.upper()
6559
6560        this = self._parse_bitwise()
6561        if self._match_set((TokenType.FROM, TokenType.COMMA)):
6562            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
6563            expression = self._parse_bitwise()
6564
6565            if invert_order:
6566                this, expression = expression, this
6567
6568        if self._match(TokenType.COLLATE):
6569            collation = self._parse_bitwise()
6570
6571        return self.expression(
6572            exp.Trim, this=this, position=position, expression=expression, collation=collation
6573        )
6574
6575    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
6576        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
6577
6578    def _parse_named_window(self) -> t.Optional[exp.Expression]:
6579        return self._parse_window(self._parse_id_var(), alias=True)
6580
6581    def _parse_respect_or_ignore_nulls(
6582        self, this: t.Optional[exp.Expression]
6583    ) -> t.Optional[exp.Expression]:
6584        if self._match_text_seq("IGNORE", "NULLS"):
6585            return self.expression(exp.IgnoreNulls, this=this)
6586        if self._match_text_seq("RESPECT", "NULLS"):
6587            return self.expression(exp.RespectNulls, this=this)
6588        return this
6589
6590    def _parse_having_max(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
6591        if self._match(TokenType.HAVING):
6592            self._match_texts(("MAX", "MIN"))
6593            max = self._prev.text.upper() != "MIN"
6594            return self.expression(
6595                exp.HavingMax, this=this, expression=self._parse_column(), max=max
6596            )
6597
6598        return this
6599
6600    def _parse_window(
6601        self, this: t.Optional[exp.Expression], alias: bool = False
6602    ) -> t.Optional[exp.Expression]:
6603        func = this
6604        comments = func.comments if isinstance(func, exp.Expression) else None
6605
6606        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
6607        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
6608        if self._match_text_seq("WITHIN", "GROUP"):
6609            order = self._parse_wrapped(self._parse_order)
6610            this = self.expression(exp.WithinGroup, this=this, expression=order)
6611
6612        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
6613            self._match(TokenType.WHERE)
6614            this = self.expression(
6615                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
6616            )
6617            self._match_r_paren()
6618
6619        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
6620        # Some dialects choose to implement and some do not.
6621        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
6622
6623        # There is some code above in _parse_lambda that handles
6624        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
6625
6626        # The below changes handle
6627        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
6628
6629        # Oracle allows both formats
6630        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
6631        #   and Snowflake chose to do the same for familiarity
6632        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
6633        if isinstance(this, exp.AggFunc):
6634            ignore_respect = this.find(exp.IgnoreNulls, exp.RespectNulls)
6635
6636            if ignore_respect and ignore_respect is not this:
6637                ignore_respect.replace(ignore_respect.this)
6638                this = self.expression(ignore_respect.__class__, this=this)
6639
6640        this = self._parse_respect_or_ignore_nulls(this)
6641
6642        # bigquery select from window x AS (partition by ...)
6643        if alias:
6644            over = None
6645            self._match(TokenType.ALIAS)
6646        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
6647            return this
6648        else:
6649            over = self._prev.text.upper()
6650
6651        if comments and isinstance(func, exp.Expression):
6652            func.pop_comments()
6653
6654        if not self._match(TokenType.L_PAREN):
6655            return self.expression(
6656                exp.Window,
6657                comments=comments,
6658                this=this,
6659                alias=self._parse_id_var(False),
6660                over=over,
6661            )
6662
6663        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
6664
6665        first = self._match(TokenType.FIRST)
6666        if self._match_text_seq("LAST"):
6667            first = False
6668
6669        partition, order = self._parse_partition_and_order()
6670        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
6671
6672        if kind:
6673            self._match(TokenType.BETWEEN)
6674            start = self._parse_window_spec()
6675            self._match(TokenType.AND)
6676            end = self._parse_window_spec()
6677
6678            spec = self.expression(
6679                exp.WindowSpec,
6680                kind=kind,
6681                start=start["value"],
6682                start_side=start["side"],
6683                end=end["value"],
6684                end_side=end["side"],
6685            )
6686        else:
6687            spec = None
6688
6689        self._match_r_paren()
6690
6691        window = self.expression(
6692            exp.Window,
6693            comments=comments,
6694            this=this,
6695            partition_by=partition,
6696            order=order,
6697            spec=spec,
6698            alias=window_alias,
6699            over=over,
6700            first=first,
6701        )
6702
6703        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
6704        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
6705            return self._parse_window(window, alias=alias)
6706
6707        return window
6708
6709    def _parse_partition_and_order(
6710        self,
6711    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
6712        return self._parse_partition_by(), self._parse_order()
6713
6714    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
6715        self._match(TokenType.BETWEEN)
6716
6717        return {
6718            "value": (
6719                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
6720                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
6721                or self._parse_bitwise()
6722            ),
6723            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
6724        }
6725
6726    def _parse_alias(
6727        self, this: t.Optional[exp.Expression], explicit: bool = False
6728    ) -> t.Optional[exp.Expression]:
6729        # In some dialects, LIMIT and OFFSET can act as both identifiers and keywords (clauses)
6730        # so this section tries to parse the clause version and if it fails, it treats the token
6731        # as an identifier (alias)
6732        if self._can_parse_limit_or_offset():
6733            return this
6734
6735        any_token = self._match(TokenType.ALIAS)
6736        comments = self._prev_comments or []
6737
6738        if explicit and not any_token:
6739            return this
6740
6741        if self._match(TokenType.L_PAREN):
6742            aliases = self.expression(
6743                exp.Aliases,
6744                comments=comments,
6745                this=this,
6746                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
6747            )
6748            self._match_r_paren(aliases)
6749            return aliases
6750
6751        alias = self._parse_id_var(any_token, tokens=self.ALIAS_TOKENS) or (
6752            self.STRING_ALIASES and self._parse_string_as_identifier()
6753        )
6754
6755        if alias:
6756            comments.extend(alias.pop_comments())
6757            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
6758            column = this.this
6759
6760            # Moves the comment next to the alias in `expr /* comment */ AS alias`
6761            if not this.comments and column and column.comments:
6762                this.comments = column.pop_comments()
6763
6764        return this
6765
6766    def _parse_id_var(
6767        self,
6768        any_token: bool = True,
6769        tokens: t.Optional[t.Collection[TokenType]] = None,
6770    ) -> t.Optional[exp.Expression]:
6771        expression = self._parse_identifier()
6772        if not expression and (
6773            (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS)
6774        ):
6775            quoted = self._prev.token_type == TokenType.STRING
6776            expression = self.expression(exp.Identifier, this=self._prev.text, quoted=quoted)
6777
6778        return expression
6779
6780    def _parse_string(self) -> t.Optional[exp.Expression]:
6781        if self._match_set(self.STRING_PARSERS):
6782            return self.STRING_PARSERS[self._prev.token_type](self, self._prev)
6783        return self._parse_placeholder()
6784
6785    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
6786        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
6787
6788    def _parse_number(self) -> t.Optional[exp.Expression]:
6789        if self._match_set(self.NUMERIC_PARSERS):
6790            return self.NUMERIC_PARSERS[self._prev.token_type](self, self._prev)
6791        return self._parse_placeholder()
6792
6793    def _parse_identifier(self) -> t.Optional[exp.Expression]:
6794        if self._match(TokenType.IDENTIFIER):
6795            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
6796        return self._parse_placeholder()
6797
6798    def _parse_var(
6799        self,
6800        any_token: bool = False,
6801        tokens: t.Optional[t.Collection[TokenType]] = None,
6802        upper: bool = False,
6803    ) -> t.Optional[exp.Expression]:
6804        if (
6805            (any_token and self._advance_any())
6806            or self._match(TokenType.VAR)
6807            or (self._match_set(tokens) if tokens else False)
6808        ):
6809            return self.expression(
6810                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
6811            )
6812        return self._parse_placeholder()
6813
6814    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
6815        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
6816            self._advance()
6817            return self._prev
6818        return None
6819
6820    def _parse_var_or_string(self, upper: bool = False) -> t.Optional[exp.Expression]:
6821        return self._parse_string() or self._parse_var(any_token=True, upper=upper)
6822
6823    def _parse_primary_or_var(self) -> t.Optional[exp.Expression]:
6824        return self._parse_primary() or self._parse_var(any_token=True)
6825
6826    def _parse_null(self) -> t.Optional[exp.Expression]:
6827        if self._match_set(self.NULL_TOKENS):
6828            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
6829        return self._parse_placeholder()
6830
6831    def _parse_boolean(self) -> t.Optional[exp.Expression]:
6832        if self._match(TokenType.TRUE):
6833            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
6834        if self._match(TokenType.FALSE):
6835            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
6836        return self._parse_placeholder()
6837
6838    def _parse_star(self) -> t.Optional[exp.Expression]:
6839        if self._match(TokenType.STAR):
6840            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
6841        return self._parse_placeholder()
6842
6843    def _parse_parameter(self) -> exp.Parameter:
6844        this = self._parse_identifier() or self._parse_primary_or_var()
6845        return self.expression(exp.Parameter, this=this)
6846
6847    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
6848        if self._match_set(self.PLACEHOLDER_PARSERS):
6849            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
6850            if placeholder:
6851                return placeholder
6852            self._advance(-1)
6853        return None
6854
6855    def _parse_star_op(self, *keywords: str) -> t.Optional[t.List[exp.Expression]]:
6856        if not self._match_texts(keywords):
6857            return None
6858        if self._match(TokenType.L_PAREN, advance=False):
6859            return self._parse_wrapped_csv(self._parse_expression)
6860
6861        expression = self._parse_expression()
6862        return [expression] if expression else None
6863
6864    def _parse_csv(
6865        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
6866    ) -> t.List[exp.Expression]:
6867        parse_result = parse_method()
6868        items = [parse_result] if parse_result is not None else []
6869
6870        while self._match(sep):
6871            self._add_comments(parse_result)
6872            parse_result = parse_method()
6873            if parse_result is not None:
6874                items.append(parse_result)
6875
6876        return items
6877
6878    def _parse_tokens(
6879        self, parse_method: t.Callable, expressions: t.Dict
6880    ) -> t.Optional[exp.Expression]:
6881        this = parse_method()
6882
6883        while self._match_set(expressions):
6884            this = self.expression(
6885                expressions[self._prev.token_type],
6886                this=this,
6887                comments=self._prev_comments,
6888                expression=parse_method(),
6889            )
6890
6891        return this
6892
6893    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
6894        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
6895
6896    def _parse_wrapped_csv(
6897        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
6898    ) -> t.List[exp.Expression]:
6899        return self._parse_wrapped(
6900            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
6901        )
6902
6903    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
6904        wrapped = self._match(TokenType.L_PAREN)
6905        if not wrapped and not optional:
6906            self.raise_error("Expecting (")
6907        parse_result = parse_method()
6908        if wrapped:
6909            self._match_r_paren()
6910        return parse_result
6911
6912    def _parse_expressions(self) -> t.List[exp.Expression]:
6913        return self._parse_csv(self._parse_expression)
6914
6915    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
6916        return self._parse_select() or self._parse_set_operations(
6917            self._parse_alias(self._parse_assignment(), explicit=True)
6918            if alias
6919            else self._parse_assignment()
6920        )
6921
6922    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
6923        return self._parse_query_modifiers(
6924            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
6925        )
6926
6927    def _parse_transaction(self) -> exp.Transaction | exp.Command:
6928        this = None
6929        if self._match_texts(self.TRANSACTION_KIND):
6930            this = self._prev.text
6931
6932        self._match_texts(("TRANSACTION", "WORK"))
6933
6934        modes = []
6935        while True:
6936            mode = []
6937            while self._match(TokenType.VAR):
6938                mode.append(self._prev.text)
6939
6940            if mode:
6941                modes.append(" ".join(mode))
6942            if not self._match(TokenType.COMMA):
6943                break
6944
6945        return self.expression(exp.Transaction, this=this, modes=modes)
6946
6947    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
6948        chain = None
6949        savepoint = None
6950        is_rollback = self._prev.token_type == TokenType.ROLLBACK
6951
6952        self._match_texts(("TRANSACTION", "WORK"))
6953
6954        if self._match_text_seq("TO"):
6955            self._match_text_seq("SAVEPOINT")
6956            savepoint = self._parse_id_var()
6957
6958        if self._match(TokenType.AND):
6959            chain = not self._match_text_seq("NO")
6960            self._match_text_seq("CHAIN")
6961
6962        if is_rollback:
6963            return self.expression(exp.Rollback, savepoint=savepoint)
6964
6965        return self.expression(exp.Commit, chain=chain)
6966
6967    def _parse_refresh(self) -> exp.Refresh:
6968        self._match(TokenType.TABLE)
6969        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
6970
6971    def _parse_add_column(self) -> t.Optional[exp.Expression]:
6972        if not self._match_text_seq("ADD"):
6973            return None
6974
6975        self._match(TokenType.COLUMN)
6976        exists_column = self._parse_exists(not_=True)
6977        expression = self._parse_field_def()
6978
6979        if expression:
6980            expression.set("exists", exists_column)
6981
6982            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
6983            if self._match_texts(("FIRST", "AFTER")):
6984                position = self._prev.text
6985                column_position = self.expression(
6986                    exp.ColumnPosition, this=self._parse_column(), position=position
6987                )
6988                expression.set("position", column_position)
6989
6990        return expression
6991
6992    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
6993        drop = self._match(TokenType.DROP) and self._parse_drop()
6994        if drop and not isinstance(drop, exp.Command):
6995            drop.set("kind", drop.args.get("kind", "COLUMN"))
6996        return drop
6997
6998    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
6999    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
7000        return self.expression(
7001            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
7002        )
7003
7004    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
7005        index = self._index - 1
7006
7007        if self._match_set(self.ADD_CONSTRAINT_TOKENS, advance=False):
7008            return self._parse_csv(
7009                lambda: self.expression(
7010                    exp.AddConstraint, expressions=self._parse_csv(self._parse_constraint)
7011                )
7012            )
7013
7014        self._retreat(index)
7015        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
7016            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
7017
7018        if self._match_text_seq("ADD", "COLUMNS"):
7019            schema = self._parse_schema()
7020            if schema:
7021                return [schema]
7022            return []
7023
7024        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
7025
7026    def _parse_alter_table_alter(self) -> t.Optional[exp.Expression]:
7027        if self._match_texts(self.ALTER_ALTER_PARSERS):
7028            return self.ALTER_ALTER_PARSERS[self._prev.text.upper()](self)
7029
7030        # Many dialects support the ALTER [COLUMN] syntax, so if there is no
7031        # keyword after ALTER we default to parsing this statement
7032        self._match(TokenType.COLUMN)
7033        column = self._parse_field(any_token=True)
7034
7035        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
7036            return self.expression(exp.AlterColumn, this=column, drop=True)
7037        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
7038            return self.expression(exp.AlterColumn, this=column, default=self._parse_assignment())
7039        if self._match(TokenType.COMMENT):
7040            return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
7041        if self._match_text_seq("DROP", "NOT", "NULL"):
7042            return self.expression(
7043                exp.AlterColumn,
7044                this=column,
7045                drop=True,
7046                allow_null=True,
7047            )
7048        if self._match_text_seq("SET", "NOT", "NULL"):
7049            return self.expression(
7050                exp.AlterColumn,
7051                this=column,
7052                allow_null=False,
7053            )
7054        self._match_text_seq("SET", "DATA")
7055        self._match_text_seq("TYPE")
7056        return self.expression(
7057            exp.AlterColumn,
7058            this=column,
7059            dtype=self._parse_types(),
7060            collate=self._match(TokenType.COLLATE) and self._parse_term(),
7061            using=self._match(TokenType.USING) and self._parse_assignment(),
7062        )
7063
7064    def _parse_alter_diststyle(self) -> exp.AlterDistStyle:
7065        if self._match_texts(("ALL", "EVEN", "AUTO")):
7066            return self.expression(exp.AlterDistStyle, this=exp.var(self._prev.text.upper()))
7067
7068        self._match_text_seq("KEY", "DISTKEY")
7069        return self.expression(exp.AlterDistStyle, this=self._parse_column())
7070
7071    def _parse_alter_sortkey(self, compound: t.Optional[bool] = None) -> exp.AlterSortKey:
7072        if compound:
7073            self._match_text_seq("SORTKEY")
7074
7075        if self._match(TokenType.L_PAREN, advance=False):
7076            return self.expression(
7077                exp.AlterSortKey, expressions=self._parse_wrapped_id_vars(), compound=compound
7078            )
7079
7080        self._match_texts(("AUTO", "NONE"))
7081        return self.expression(
7082            exp.AlterSortKey, this=exp.var(self._prev.text.upper()), compound=compound
7083        )
7084
7085    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
7086        index = self._index - 1
7087
7088        partition_exists = self._parse_exists()
7089        if self._match(TokenType.PARTITION, advance=False):
7090            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
7091
7092        self._retreat(index)
7093        return self._parse_csv(self._parse_drop_column)
7094
7095    def _parse_alter_table_rename(self) -> t.Optional[exp.AlterRename | exp.RenameColumn]:
7096        if self._match(TokenType.COLUMN):
7097            exists = self._parse_exists()
7098            old_column = self._parse_column()
7099            to = self._match_text_seq("TO")
7100            new_column = self._parse_column()
7101
7102            if old_column is None or to is None or new_column is None:
7103                return None
7104
7105            return self.expression(exp.RenameColumn, this=old_column, to=new_column, exists=exists)
7106
7107        self._match_text_seq("TO")
7108        return self.expression(exp.AlterRename, this=self._parse_table(schema=True))
7109
7110    def _parse_alter_table_set(self) -> exp.AlterSet:
7111        alter_set = self.expression(exp.AlterSet)
7112
7113        if self._match(TokenType.L_PAREN, advance=False) or self._match_text_seq(
7114            "TABLE", "PROPERTIES"
7115        ):
7116            alter_set.set("expressions", self._parse_wrapped_csv(self._parse_assignment))
7117        elif self._match_text_seq("FILESTREAM_ON", advance=False):
7118            alter_set.set("expressions", [self._parse_assignment()])
7119        elif self._match_texts(("LOGGED", "UNLOGGED")):
7120            alter_set.set("option", exp.var(self._prev.text.upper()))
7121        elif self._match_text_seq("WITHOUT") and self._match_texts(("CLUSTER", "OIDS")):
7122            alter_set.set("option", exp.var(f"WITHOUT {self._prev.text.upper()}"))
7123        elif self._match_text_seq("LOCATION"):
7124            alter_set.set("location", self._parse_field())
7125        elif self._match_text_seq("ACCESS", "METHOD"):
7126            alter_set.set("access_method", self._parse_field())
7127        elif self._match_text_seq("TABLESPACE"):
7128            alter_set.set("tablespace", self._parse_field())
7129        elif self._match_text_seq("FILE", "FORMAT") or self._match_text_seq("FILEFORMAT"):
7130            alter_set.set("file_format", [self._parse_field()])
7131        elif self._match_text_seq("STAGE_FILE_FORMAT"):
7132            alter_set.set("file_format", self._parse_wrapped_options())
7133        elif self._match_text_seq("STAGE_COPY_OPTIONS"):
7134            alter_set.set("copy_options", self._parse_wrapped_options())
7135        elif self._match_text_seq("TAG") or self._match_text_seq("TAGS"):
7136            alter_set.set("tag", self._parse_csv(self._parse_assignment))
7137        else:
7138            if self._match_text_seq("SERDE"):
7139                alter_set.set("serde", self._parse_field())
7140
7141            alter_set.set("expressions", [self._parse_properties()])
7142
7143        return alter_set
7144
7145    def _parse_alter(self) -> exp.Alter | exp.Command:
7146        start = self._prev
7147
7148        alter_token = self._match_set(self.ALTERABLES) and self._prev
7149        if not alter_token:
7150            return self._parse_as_command(start)
7151
7152        exists = self._parse_exists()
7153        only = self._match_text_seq("ONLY")
7154        this = self._parse_table(schema=True)
7155        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
7156
7157        if self._next:
7158            self._advance()
7159
7160        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
7161        if parser:
7162            actions = ensure_list(parser(self))
7163            not_valid = self._match_text_seq("NOT", "VALID")
7164            options = self._parse_csv(self._parse_property)
7165
7166            if not self._curr and actions:
7167                return self.expression(
7168                    exp.Alter,
7169                    this=this,
7170                    kind=alter_token.text.upper(),
7171                    exists=exists,
7172                    actions=actions,
7173                    only=only,
7174                    options=options,
7175                    cluster=cluster,
7176                    not_valid=not_valid,
7177                )
7178
7179        return self._parse_as_command(start)
7180
7181    def _parse_analyze(self) -> exp.Analyze | exp.Command:
7182        start = self._prev
7183        # https://duckdb.org/docs/sql/statements/analyze
7184        if not self._curr:
7185            return self.expression(exp.Analyze)
7186
7187        options = []
7188        while self._match_texts(self.ANALYZE_STYLES):
7189            if self._prev.text.upper() == "BUFFER_USAGE_LIMIT":
7190                options.append(f"BUFFER_USAGE_LIMIT {self._parse_number()}")
7191            else:
7192                options.append(self._prev.text.upper())
7193
7194        this: t.Optional[exp.Expression] = None
7195        inner_expression: t.Optional[exp.Expression] = None
7196
7197        kind = self._curr and self._curr.text.upper()
7198
7199        if self._match(TokenType.TABLE) or self._match(TokenType.INDEX):
7200            this = self._parse_table_parts()
7201        elif self._match_text_seq("TABLES"):
7202            if self._match_set((TokenType.FROM, TokenType.IN)):
7203                kind = f"{kind} {self._prev.text.upper()}"
7204                this = self._parse_table(schema=True, is_db_reference=True)
7205        elif self._match_text_seq("DATABASE"):
7206            this = self._parse_table(schema=True, is_db_reference=True)
7207        elif self._match_text_seq("CLUSTER"):
7208            this = self._parse_table()
7209        # Try matching inner expr keywords before fallback to parse table.
7210        elif self._match_texts(self.ANALYZE_EXPRESSION_PARSERS):
7211            kind = None
7212            inner_expression = self.ANALYZE_EXPRESSION_PARSERS[self._prev.text.upper()](self)
7213        else:
7214            # Empty kind  https://prestodb.io/docs/current/sql/analyze.html
7215            kind = None
7216            this = self._parse_table_parts()
7217
7218        partition = self._try_parse(self._parse_partition)
7219        if not partition and self._match_texts(self.PARTITION_KEYWORDS):
7220            return self._parse_as_command(start)
7221
7222        # https://docs.starrocks.io/docs/sql-reference/sql-statements/cbo_stats/ANALYZE_TABLE/
7223        if self._match_text_seq("WITH", "SYNC", "MODE") or self._match_text_seq(
7224            "WITH", "ASYNC", "MODE"
7225        ):
7226            mode = f"WITH {self._tokens[self._index-2].text.upper()} MODE"
7227        else:
7228            mode = None
7229
7230        if self._match_texts(self.ANALYZE_EXPRESSION_PARSERS):
7231            inner_expression = self.ANALYZE_EXPRESSION_PARSERS[self._prev.text.upper()](self)
7232
7233        properties = self._parse_properties()
7234        return self.expression(
7235            exp.Analyze,
7236            kind=kind,
7237            this=this,
7238            mode=mode,
7239            partition=partition,
7240            properties=properties,
7241            expression=inner_expression,
7242            options=options,
7243        )
7244
7245    # https://spark.apache.org/docs/3.5.1/sql-ref-syntax-aux-analyze-table.html
7246    def _parse_analyze_statistics(self) -> exp.AnalyzeStatistics:
7247        this = None
7248        kind = self._prev.text.upper()
7249        option = self._prev.text.upper() if self._match_text_seq("DELTA") else None
7250        expressions = []
7251
7252        if not self._match_text_seq("STATISTICS"):
7253            self.raise_error("Expecting token STATISTICS")
7254
7255        if self._match_text_seq("NOSCAN"):
7256            this = "NOSCAN"
7257        elif self._match(TokenType.FOR):
7258            if self._match_text_seq("ALL", "COLUMNS"):
7259                this = "FOR ALL COLUMNS"
7260            if self._match_texts("COLUMNS"):
7261                this = "FOR COLUMNS"
7262                expressions = self._parse_csv(self._parse_column_reference)
7263        elif self._match_text_seq("SAMPLE"):
7264            sample = self._parse_number()
7265            expressions = [
7266                self.expression(
7267                    exp.AnalyzeSample,
7268                    sample=sample,
7269                    kind=self._prev.text.upper() if self._match(TokenType.PERCENT) else None,
7270                )
7271            ]
7272
7273        return self.expression(
7274            exp.AnalyzeStatistics, kind=kind, option=option, this=this, expressions=expressions
7275        )
7276
7277    # https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/ANALYZE.html
7278    def _parse_analyze_validate(self) -> exp.AnalyzeValidate:
7279        kind = None
7280        this = None
7281        expression: t.Optional[exp.Expression] = None
7282        if self._match_text_seq("REF", "UPDATE"):
7283            kind = "REF"
7284            this = "UPDATE"
7285            if self._match_text_seq("SET", "DANGLING", "TO", "NULL"):
7286                this = "UPDATE SET DANGLING TO NULL"
7287        elif self._match_text_seq("STRUCTURE"):
7288            kind = "STRUCTURE"
7289            if self._match_text_seq("CASCADE", "FAST"):
7290                this = "CASCADE FAST"
7291            elif self._match_text_seq("CASCADE", "COMPLETE") and self._match_texts(
7292                ("ONLINE", "OFFLINE")
7293            ):
7294                this = f"CASCADE COMPLETE {self._prev.text.upper()}"
7295                expression = self._parse_into()
7296
7297        return self.expression(exp.AnalyzeValidate, kind=kind, this=this, expression=expression)
7298
7299    def _parse_analyze_columns(self) -> t.Optional[exp.AnalyzeColumns]:
7300        this = self._prev.text.upper()
7301        if self._match_text_seq("COLUMNS"):
7302            return self.expression(exp.AnalyzeColumns, this=f"{this} {self._prev.text.upper()}")
7303        return None
7304
7305    def _parse_analyze_delete(self) -> t.Optional[exp.AnalyzeDelete]:
7306        kind = self._prev.text.upper() if self._match_text_seq("SYSTEM") else None
7307        if self._match_text_seq("STATISTICS"):
7308            return self.expression(exp.AnalyzeDelete, kind=kind)
7309        return None
7310
7311    def _parse_analyze_list(self) -> t.Optional[exp.AnalyzeListChainedRows]:
7312        if self._match_text_seq("CHAINED", "ROWS"):
7313            return self.expression(exp.AnalyzeListChainedRows, expression=self._parse_into())
7314        return None
7315
7316    # https://dev.mysql.com/doc/refman/8.4/en/analyze-table.html
7317    def _parse_analyze_histogram(self) -> exp.AnalyzeHistogram:
7318        this = self._prev.text.upper()
7319        expression: t.Optional[exp.Expression] = None
7320        expressions = []
7321        update_options = None
7322
7323        if self._match_text_seq("HISTOGRAM", "ON"):
7324            expressions = self._parse_csv(self._parse_column_reference)
7325            with_expressions = []
7326            while self._match(TokenType.WITH):
7327                # https://docs.starrocks.io/docs/sql-reference/sql-statements/cbo_stats/ANALYZE_TABLE/
7328                if self._match_texts(("SYNC", "ASYNC")):
7329                    if self._match_text_seq("MODE", advance=False):
7330                        with_expressions.append(f"{self._prev.text.upper()} MODE")
7331                        self._advance()
7332                else:
7333                    buckets = self._parse_number()
7334                    if self._match_text_seq("BUCKETS"):
7335                        with_expressions.append(f"{buckets} BUCKETS")
7336            if with_expressions:
7337                expression = self.expression(exp.AnalyzeWith, expressions=with_expressions)
7338
7339            if self._match_texts(("MANUAL", "AUTO")) and self._match(
7340                TokenType.UPDATE, advance=False
7341            ):
7342                update_options = self._prev.text.upper()
7343                self._advance()
7344            elif self._match_text_seq("USING", "DATA"):
7345                expression = self.expression(exp.UsingData, this=self._parse_string())
7346
7347        return self.expression(
7348            exp.AnalyzeHistogram,
7349            this=this,
7350            expressions=expressions,
7351            expression=expression,
7352            update_options=update_options,
7353        )
7354
7355    def _parse_merge(self) -> exp.Merge:
7356        self._match(TokenType.INTO)
7357        target = self._parse_table()
7358
7359        if target and self._match(TokenType.ALIAS, advance=False):
7360            target.set("alias", self._parse_table_alias())
7361
7362        self._match(TokenType.USING)
7363        using = self._parse_table()
7364
7365        self._match(TokenType.ON)
7366        on = self._parse_assignment()
7367
7368        return self.expression(
7369            exp.Merge,
7370            this=target,
7371            using=using,
7372            on=on,
7373            whens=self._parse_when_matched(),
7374            returning=self._parse_returning(),
7375        )
7376
7377    def _parse_when_matched(self) -> exp.Whens:
7378        whens = []
7379
7380        while self._match(TokenType.WHEN):
7381            matched = not self._match(TokenType.NOT)
7382            self._match_text_seq("MATCHED")
7383            source = (
7384                False
7385                if self._match_text_seq("BY", "TARGET")
7386                else self._match_text_seq("BY", "SOURCE")
7387            )
7388            condition = self._parse_assignment() if self._match(TokenType.AND) else None
7389
7390            self._match(TokenType.THEN)
7391
7392            if self._match(TokenType.INSERT):
7393                this = self._parse_star()
7394                if this:
7395                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=this)
7396                else:
7397                    then = self.expression(
7398                        exp.Insert,
7399                        this=exp.var("ROW") if self._match_text_seq("ROW") else self._parse_value(),
7400                        expression=self._match_text_seq("VALUES") and self._parse_value(),
7401                    )
7402            elif self._match(TokenType.UPDATE):
7403                expressions = self._parse_star()
7404                if expressions:
7405                    then = self.expression(exp.Update, expressions=expressions)
7406                else:
7407                    then = self.expression(
7408                        exp.Update,
7409                        expressions=self._match(TokenType.SET)
7410                        and self._parse_csv(self._parse_equality),
7411                    )
7412            elif self._match(TokenType.DELETE):
7413                then = self.expression(exp.Var, this=self._prev.text)
7414            else:
7415                then = self._parse_var_from_options(self.CONFLICT_ACTIONS)
7416
7417            whens.append(
7418                self.expression(
7419                    exp.When,
7420                    matched=matched,
7421                    source=source,
7422                    condition=condition,
7423                    then=then,
7424                )
7425            )
7426        return self.expression(exp.Whens, expressions=whens)
7427
7428    def _parse_show(self) -> t.Optional[exp.Expression]:
7429        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
7430        if parser:
7431            return parser(self)
7432        return self._parse_as_command(self._prev)
7433
7434    def _parse_set_item_assignment(
7435        self, kind: t.Optional[str] = None
7436    ) -> t.Optional[exp.Expression]:
7437        index = self._index
7438
7439        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
7440            return self._parse_set_transaction(global_=kind == "GLOBAL")
7441
7442        left = self._parse_primary() or self._parse_column()
7443        assignment_delimiter = self._match_texts(("=", "TO"))
7444
7445        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
7446            self._retreat(index)
7447            return None
7448
7449        right = self._parse_statement() or self._parse_id_var()
7450        if isinstance(right, (exp.Column, exp.Identifier)):
7451            right = exp.var(right.name)
7452
7453        this = self.expression(exp.EQ, this=left, expression=right)
7454        return self.expression(exp.SetItem, this=this, kind=kind)
7455
7456    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
7457        self._match_text_seq("TRANSACTION")
7458        characteristics = self._parse_csv(
7459            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
7460        )
7461        return self.expression(
7462            exp.SetItem,
7463            expressions=characteristics,
7464            kind="TRANSACTION",
7465            **{"global": global_},  # type: ignore
7466        )
7467
7468    def _parse_set_item(self) -> t.Optional[exp.Expression]:
7469        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
7470        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
7471
7472    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
7473        index = self._index
7474        set_ = self.expression(
7475            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
7476        )
7477
7478        if self._curr:
7479            self._retreat(index)
7480            return self._parse_as_command(self._prev)
7481
7482        return set_
7483
7484    def _parse_var_from_options(
7485        self, options: OPTIONS_TYPE, raise_unmatched: bool = True
7486    ) -> t.Optional[exp.Var]:
7487        start = self._curr
7488        if not start:
7489            return None
7490
7491        option = start.text.upper()
7492        continuations = options.get(option)
7493
7494        index = self._index
7495        self._advance()
7496        for keywords in continuations or []:
7497            if isinstance(keywords, str):
7498                keywords = (keywords,)
7499
7500            if self._match_text_seq(*keywords):
7501                option = f"{option} {' '.join(keywords)}"
7502                break
7503        else:
7504            if continuations or continuations is None:
7505                if raise_unmatched:
7506                    self.raise_error(f"Unknown option {option}")
7507
7508                self._retreat(index)
7509                return None
7510
7511        return exp.var(option)
7512
7513    def _parse_as_command(self, start: Token) -> exp.Command:
7514        while self._curr:
7515            self._advance()
7516        text = self._find_sql(start, self._prev)
7517        size = len(start.text)
7518        self._warn_unsupported()
7519        return exp.Command(this=text[:size], expression=text[size:])
7520
7521    def _parse_dict_property(self, this: str) -> exp.DictProperty:
7522        settings = []
7523
7524        self._match_l_paren()
7525        kind = self._parse_id_var()
7526
7527        if self._match(TokenType.L_PAREN):
7528            while True:
7529                key = self._parse_id_var()
7530                value = self._parse_primary()
7531                if not key and value is None:
7532                    break
7533                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
7534            self._match(TokenType.R_PAREN)
7535
7536        self._match_r_paren()
7537
7538        return self.expression(
7539            exp.DictProperty,
7540            this=this,
7541            kind=kind.this if kind else None,
7542            settings=settings,
7543        )
7544
7545    def _parse_dict_range(self, this: str) -> exp.DictRange:
7546        self._match_l_paren()
7547        has_min = self._match_text_seq("MIN")
7548        if has_min:
7549            min = self._parse_var() or self._parse_primary()
7550            self._match_text_seq("MAX")
7551            max = self._parse_var() or self._parse_primary()
7552        else:
7553            max = self._parse_var() or self._parse_primary()
7554            min = exp.Literal.number(0)
7555        self._match_r_paren()
7556        return self.expression(exp.DictRange, this=this, min=min, max=max)
7557
7558    def _parse_comprehension(
7559        self, this: t.Optional[exp.Expression]
7560    ) -> t.Optional[exp.Comprehension]:
7561        index = self._index
7562        expression = self._parse_column()
7563        if not self._match(TokenType.IN):
7564            self._retreat(index - 1)
7565            return None
7566        iterator = self._parse_column()
7567        condition = self._parse_assignment() if self._match_text_seq("IF") else None
7568        return self.expression(
7569            exp.Comprehension,
7570            this=this,
7571            expression=expression,
7572            iterator=iterator,
7573            condition=condition,
7574        )
7575
7576    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
7577        if self._match(TokenType.HEREDOC_STRING):
7578            return self.expression(exp.Heredoc, this=self._prev.text)
7579
7580        if not self._match_text_seq("$"):
7581            return None
7582
7583        tags = ["$"]
7584        tag_text = None
7585
7586        if self._is_connected():
7587            self._advance()
7588            tags.append(self._prev.text.upper())
7589        else:
7590            self.raise_error("No closing $ found")
7591
7592        if tags[-1] != "$":
7593            if self._is_connected() and self._match_text_seq("$"):
7594                tag_text = tags[-1]
7595                tags.append("$")
7596            else:
7597                self.raise_error("No closing $ found")
7598
7599        heredoc_start = self._curr
7600
7601        while self._curr:
7602            if self._match_text_seq(*tags, advance=False):
7603                this = self._find_sql(heredoc_start, self._prev)
7604                self._advance(len(tags))
7605                return self.expression(exp.Heredoc, this=this, tag=tag_text)
7606
7607            self._advance()
7608
7609        self.raise_error(f"No closing {''.join(tags)} found")
7610        return None
7611
7612    def _find_parser(
7613        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
7614    ) -> t.Optional[t.Callable]:
7615        if not self._curr:
7616            return None
7617
7618        index = self._index
7619        this = []
7620        while True:
7621            # The current token might be multiple words
7622            curr = self._curr.text.upper()
7623            key = curr.split(" ")
7624            this.append(curr)
7625
7626            self._advance()
7627            result, trie = in_trie(trie, key)
7628            if result == TrieResult.FAILED:
7629                break
7630
7631            if result == TrieResult.EXISTS:
7632                subparser = parsers[" ".join(this)]
7633                return subparser
7634
7635        self._retreat(index)
7636        return None
7637
7638    def _match(self, token_type, advance=True, expression=None):
7639        if not self._curr:
7640            return None
7641
7642        if self._curr.token_type == token_type:
7643            if advance:
7644                self._advance()
7645            self._add_comments(expression)
7646            return True
7647
7648        return None
7649
7650    def _match_set(self, types, advance=True):
7651        if not self._curr:
7652            return None
7653
7654        if self._curr.token_type in types:
7655            if advance:
7656                self._advance()
7657            return True
7658
7659        return None
7660
7661    def _match_pair(self, token_type_a, token_type_b, advance=True):
7662        if not self._curr or not self._next:
7663            return None
7664
7665        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
7666            if advance:
7667                self._advance(2)
7668            return True
7669
7670        return None
7671
7672    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
7673        if not self._match(TokenType.L_PAREN, expression=expression):
7674            self.raise_error("Expecting (")
7675
7676    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
7677        if not self._match(TokenType.R_PAREN, expression=expression):
7678            self.raise_error("Expecting )")
7679
7680    def _match_texts(self, texts, advance=True):
7681        if (
7682            self._curr
7683            and self._curr.token_type != TokenType.STRING
7684            and self._curr.text.upper() in texts
7685        ):
7686            if advance:
7687                self._advance()
7688            return True
7689        return None
7690
7691    def _match_text_seq(self, *texts, advance=True):
7692        index = self._index
7693        for text in texts:
7694            if (
7695                self._curr
7696                and self._curr.token_type != TokenType.STRING
7697                and self._curr.text.upper() == text
7698            ):
7699                self._advance()
7700            else:
7701                self._retreat(index)
7702                return None
7703
7704        if not advance:
7705            self._retreat(index)
7706
7707        return True
7708
7709    def _replace_lambda(
7710        self, node: t.Optional[exp.Expression], expressions: t.List[exp.Expression]
7711    ) -> t.Optional[exp.Expression]:
7712        if not node:
7713            return node
7714
7715        lambda_types = {e.name: e.args.get("to") or False for e in expressions}
7716
7717        for column in node.find_all(exp.Column):
7718            typ = lambda_types.get(column.parts[0].name)
7719            if typ is not None:
7720                dot_or_id = column.to_dot() if column.table else column.this
7721
7722                if typ:
7723                    dot_or_id = self.expression(
7724                        exp.Cast,
7725                        this=dot_or_id,
7726                        to=typ,
7727                    )
7728
7729                parent = column.parent
7730
7731                while isinstance(parent, exp.Dot):
7732                    if not isinstance(parent.parent, exp.Dot):
7733                        parent.replace(dot_or_id)
7734                        break
7735                    parent = parent.parent
7736                else:
7737                    if column is node:
7738                        node = dot_or_id
7739                    else:
7740                        column.replace(dot_or_id)
7741        return node
7742
7743    def _parse_truncate_table(self) -> t.Optional[exp.TruncateTable] | exp.Expression:
7744        start = self._prev
7745
7746        # Not to be confused with TRUNCATE(number, decimals) function call
7747        if self._match(TokenType.L_PAREN):
7748            self._retreat(self._index - 2)
7749            return self._parse_function()
7750
7751        # Clickhouse supports TRUNCATE DATABASE as well
7752        is_database = self._match(TokenType.DATABASE)
7753
7754        self._match(TokenType.TABLE)
7755
7756        exists = self._parse_exists(not_=False)
7757
7758        expressions = self._parse_csv(
7759            lambda: self._parse_table(schema=True, is_db_reference=is_database)
7760        )
7761
7762        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
7763
7764        if self._match_text_seq("RESTART", "IDENTITY"):
7765            identity = "RESTART"
7766        elif self._match_text_seq("CONTINUE", "IDENTITY"):
7767            identity = "CONTINUE"
7768        else:
7769            identity = None
7770
7771        if self._match_text_seq("CASCADE") or self._match_text_seq("RESTRICT"):
7772            option = self._prev.text
7773        else:
7774            option = None
7775
7776        partition = self._parse_partition()
7777
7778        # Fallback case
7779        if self._curr:
7780            return self._parse_as_command(start)
7781
7782        return self.expression(
7783            exp.TruncateTable,
7784            expressions=expressions,
7785            is_database=is_database,
7786            exists=exists,
7787            cluster=cluster,
7788            identity=identity,
7789            option=option,
7790            partition=partition,
7791        )
7792
7793    def _parse_with_operator(self) -> t.Optional[exp.Expression]:
7794        this = self._parse_ordered(self._parse_opclass)
7795
7796        if not self._match(TokenType.WITH):
7797            return this
7798
7799        op = self._parse_var(any_token=True)
7800
7801        return self.expression(exp.WithOperator, this=this, op=op)
7802
7803    def _parse_wrapped_options(self) -> t.List[t.Optional[exp.Expression]]:
7804        self._match(TokenType.EQ)
7805        self._match(TokenType.L_PAREN)
7806
7807        opts: t.List[t.Optional[exp.Expression]] = []
7808        while self._curr and not self._match(TokenType.R_PAREN):
7809            if self._match_text_seq("FORMAT_NAME", "="):
7810                # The FORMAT_NAME can be set to an identifier for Snowflake and T-SQL,
7811                # so we parse it separately to use _parse_field()
7812                prop = self.expression(
7813                    exp.Property, this=exp.var("FORMAT_NAME"), value=self._parse_field()
7814                )
7815                opts.append(prop)
7816            else:
7817                opts.append(self._parse_property())
7818
7819            self._match(TokenType.COMMA)
7820
7821        return opts
7822
7823    def _parse_copy_parameters(self) -> t.List[exp.CopyParameter]:
7824        sep = TokenType.COMMA if self.dialect.COPY_PARAMS_ARE_CSV else None
7825
7826        options = []
7827        while self._curr and not self._match(TokenType.R_PAREN, advance=False):
7828            option = self._parse_var(any_token=True)
7829            prev = self._prev.text.upper()
7830
7831            # Different dialects might separate options and values by white space, "=" and "AS"
7832            self._match(TokenType.EQ)
7833            self._match(TokenType.ALIAS)
7834
7835            param = self.expression(exp.CopyParameter, this=option)
7836
7837            if prev in self.COPY_INTO_VARLEN_OPTIONS and self._match(
7838                TokenType.L_PAREN, advance=False
7839            ):
7840                # Snowflake FILE_FORMAT case, Databricks COPY & FORMAT options
7841                param.set("expressions", self._parse_wrapped_options())
7842            elif prev == "FILE_FORMAT":
7843                # T-SQL's external file format case
7844                param.set("expression", self._parse_field())
7845            else:
7846                param.set("expression", self._parse_unquoted_field())
7847
7848            options.append(param)
7849            self._match(sep)
7850
7851        return options
7852
7853    def _parse_credentials(self) -> t.Optional[exp.Credentials]:
7854        expr = self.expression(exp.Credentials)
7855
7856        if self._match_text_seq("STORAGE_INTEGRATION", "="):
7857            expr.set("storage", self._parse_field())
7858        if self._match_text_seq("CREDENTIALS"):
7859            # Snowflake case: CREDENTIALS = (...), Redshift case: CREDENTIALS <string>
7860            creds = (
7861                self._parse_wrapped_options() if self._match(TokenType.EQ) else self._parse_field()
7862            )
7863            expr.set("credentials", creds)
7864        if self._match_text_seq("ENCRYPTION"):
7865            expr.set("encryption", self._parse_wrapped_options())
7866        if self._match_text_seq("IAM_ROLE"):
7867            expr.set("iam_role", self._parse_field())
7868        if self._match_text_seq("REGION"):
7869            expr.set("region", self._parse_field())
7870
7871        return expr
7872
7873    def _parse_file_location(self) -> t.Optional[exp.Expression]:
7874        return self._parse_field()
7875
7876    def _parse_copy(self) -> exp.Copy | exp.Command:
7877        start = self._prev
7878
7879        self._match(TokenType.INTO)
7880
7881        this = (
7882            self._parse_select(nested=True, parse_subquery_alias=False)
7883            if self._match(TokenType.L_PAREN, advance=False)
7884            else self._parse_table(schema=True)
7885        )
7886
7887        kind = self._match(TokenType.FROM) or not self._match_text_seq("TO")
7888
7889        files = self._parse_csv(self._parse_file_location)
7890        credentials = self._parse_credentials()
7891
7892        self._match_text_seq("WITH")
7893
7894        params = self._parse_wrapped(self._parse_copy_parameters, optional=True)
7895
7896        # Fallback case
7897        if self._curr:
7898            return self._parse_as_command(start)
7899
7900        return self.expression(
7901            exp.Copy,
7902            this=this,
7903            kind=kind,
7904            credentials=credentials,
7905            files=files,
7906            params=params,
7907        )
7908
7909    def _parse_normalize(self) -> exp.Normalize:
7910        return self.expression(
7911            exp.Normalize,
7912            this=self._parse_bitwise(),
7913            form=self._match(TokenType.COMMA) and self._parse_var(),
7914        )
7915
7916    def _parse_ceil_floor(self, expr_type: t.Type[TCeilFloor]) -> TCeilFloor:
7917        args = self._parse_csv(lambda: self._parse_lambda())
7918
7919        this = seq_get(args, 0)
7920        decimals = seq_get(args, 1)
7921
7922        return expr_type(
7923            this=this, decimals=decimals, to=self._match_text_seq("TO") and self._parse_var()
7924        )
7925
7926    def _parse_star_ops(self) -> t.Optional[exp.Expression]:
7927        if self._match_text_seq("COLUMNS", "(", advance=False):
7928            this = self._parse_function()
7929            if isinstance(this, exp.Columns):
7930                this.set("unpack", True)
7931            return this
7932
7933        return self.expression(
7934            exp.Star,
7935            **{  # type: ignore
7936                "except": self._parse_star_op("EXCEPT", "EXCLUDE"),
7937                "replace": self._parse_star_op("REPLACE"),
7938                "rename": self._parse_star_op("RENAME"),
7939            },
7940        )
7941
7942    def _parse_grant_privilege(self) -> t.Optional[exp.GrantPrivilege]:
7943        privilege_parts = []
7944
7945        # Keep consuming consecutive keywords until comma (end of this privilege) or ON
7946        # (end of privilege list) or L_PAREN (start of column list) are met
7947        while self._curr and not self._match_set(self.PRIVILEGE_FOLLOW_TOKENS, advance=False):
7948            privilege_parts.append(self._curr.text.upper())
7949            self._advance()
7950
7951        this = exp.var(" ".join(privilege_parts))
7952        expressions = (
7953            self._parse_wrapped_csv(self._parse_column)
7954            if self._match(TokenType.L_PAREN, advance=False)
7955            else None
7956        )
7957
7958        return self.expression(exp.GrantPrivilege, this=this, expressions=expressions)
7959
7960    def _parse_grant_principal(self) -> t.Optional[exp.GrantPrincipal]:
7961        kind = self._match_texts(("ROLE", "GROUP")) and self._prev.text.upper()
7962        principal = self._parse_id_var()
7963
7964        if not principal:
7965            return None
7966
7967        return self.expression(exp.GrantPrincipal, this=principal, kind=kind)
7968
7969    def _parse_grant(self) -> exp.Grant | exp.Command:
7970        start = self._prev
7971
7972        privileges = self._parse_csv(self._parse_grant_privilege)
7973
7974        self._match(TokenType.ON)
7975        kind = self._match_set(self.CREATABLES) and self._prev.text.upper()
7976
7977        # Attempt to parse the securable e.g. MySQL allows names
7978        # such as "foo.*", "*.*" which are not easily parseable yet
7979        securable = self._try_parse(self._parse_table_parts)
7980
7981        if not securable or not self._match_text_seq("TO"):
7982            return self._parse_as_command(start)
7983
7984        principals = self._parse_csv(self._parse_grant_principal)
7985
7986        grant_option = self._match_text_seq("WITH", "GRANT", "OPTION")
7987
7988        if self._curr:
7989            return self._parse_as_command(start)
7990
7991        return self.expression(
7992            exp.Grant,
7993            privileges=privileges,
7994            kind=kind,
7995            securable=securable,
7996            principals=principals,
7997            grant_option=grant_option,
7998        )
7999
8000    def _parse_overlay(self) -> exp.Overlay:
8001        return self.expression(
8002            exp.Overlay,
8003            **{  # type: ignore
8004                "this": self._parse_bitwise(),
8005                "expression": self._match_text_seq("PLACING") and self._parse_bitwise(),
8006                "from": self._match_text_seq("FROM") and self._parse_bitwise(),
8007                "for": self._match_text_seq("FOR") and self._parse_bitwise(),
8008            },
8009        )
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:
27def build_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
28    if len(args) == 1 and args[0].is_star:
29        return exp.StarMap(this=args[0])
30
31    keys = []
32    values = []
33    for i in range(0, len(args), 2):
34        keys.append(args[i])
35        values.append(args[i + 1])
36
37    return exp.VarMap(keys=exp.array(*keys, copy=False), values=exp.array(*values, copy=False))
def build_like(args: List) -> sqlglot.expressions.Escape | sqlglot.expressions.Like:
40def build_like(args: t.List) -> exp.Escape | exp.Like:
41    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
42    return exp.Escape(this=like, expression=seq_get(args, 2)) if len(args) > 2 else like
def binary_range_parser( expr_type: Type[sqlglot.expressions.Expression], reverse_args: bool = False) -> Callable[[Parser, Optional[sqlglot.expressions.Expression]], Optional[sqlglot.expressions.Expression]]:
45def binary_range_parser(
46    expr_type: t.Type[exp.Expression], reverse_args: bool = False
47) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
48    def _parse_binary_range(
49        self: Parser, this: t.Optional[exp.Expression]
50    ) -> t.Optional[exp.Expression]:
51        expression = self._parse_bitwise()
52        if reverse_args:
53            this, expression = expression, this
54        return self._parse_escape(self.expression(expr_type, this=this, expression=expression))
55
56    return _parse_binary_range
def build_logarithm( args: List, dialect: sqlglot.dialects.dialect.Dialect) -> sqlglot.expressions.Func:
59def build_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
60    # Default argument order is base, expression
61    this = seq_get(args, 0)
62    expression = seq_get(args, 1)
63
64    if expression:
65        if not dialect.LOG_BASE_FIRST:
66            this, expression = expression, this
67        return exp.Log(this=this, expression=expression)
68
69    return (exp.Ln if dialect.parser_class.LOG_DEFAULTS_TO_LN else exp.Log)(this=this)
def build_hex( args: List, dialect: sqlglot.dialects.dialect.Dialect) -> sqlglot.expressions.Hex | sqlglot.expressions.LowerHex:
72def build_hex(args: t.List, dialect: Dialect) -> exp.Hex | exp.LowerHex:
73    arg = seq_get(args, 0)
74    return exp.LowerHex(this=arg) if dialect.HEX_LOWERCASE else exp.Hex(this=arg)
def build_lower(args: List) -> sqlglot.expressions.Lower | sqlglot.expressions.Hex:
77def build_lower(args: t.List) -> exp.Lower | exp.Hex:
78    # LOWER(HEX(..)) can be simplified to LowerHex to simplify its transpilation
79    arg = seq_get(args, 0)
80    return exp.LowerHex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Lower(this=arg)
def build_upper(args: List) -> sqlglot.expressions.Upper | sqlglot.expressions.Hex:
83def build_upper(args: t.List) -> exp.Upper | exp.Hex:
84    # UPPER(HEX(..)) can be simplified to Hex to simplify its transpilation
85    arg = seq_get(args, 0)
86    return exp.Hex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Upper(this=arg)
def build_extract_json_with_path( expr_type: Type[~E]) -> Callable[[List, sqlglot.dialects.dialect.Dialect], ~E]:
89def build_extract_json_with_path(expr_type: t.Type[E]) -> t.Callable[[t.List, Dialect], E]:
90    def _builder(args: t.List, dialect: Dialect) -> E:
91        expression = expr_type(
92            this=seq_get(args, 0), expression=dialect.to_json_path(seq_get(args, 1))
93        )
94        if len(args) > 2 and expr_type is exp.JSONExtract:
95            expression.set("expressions", args[2:])
96
97        return expression
98
99    return _builder
def build_mod(args: List) -> sqlglot.expressions.Mod:
102def build_mod(args: t.List) -> exp.Mod:
103    this = seq_get(args, 0)
104    expression = seq_get(args, 1)
105
106    # Wrap the operands if they are binary nodes, e.g. MOD(a + 1, 7) -> (a + 1) % 7
107    this = exp.Paren(this=this) if isinstance(this, exp.Binary) else this
108    expression = exp.Paren(this=expression) if isinstance(expression, exp.Binary) else expression
109
110    return exp.Mod(this=this, expression=expression)
def build_pad(args: List, is_left: bool = True):
113def build_pad(args: t.List, is_left: bool = True):
114    return exp.Pad(
115        this=seq_get(args, 0),
116        expression=seq_get(args, 1),
117        fill_pattern=seq_get(args, 2),
118        is_left=is_left,
119    )
def build_array_constructor( exp_class: Type[~E], args: List, bracket_kind: sqlglot.tokens.TokenType, dialect: sqlglot.dialects.dialect.Dialect) -> sqlglot.expressions.Expression:
122def build_array_constructor(
123    exp_class: t.Type[E], args: t.List, bracket_kind: TokenType, dialect: Dialect
124) -> exp.Expression:
125    array_exp = exp_class(expressions=args)
126
127    if exp_class == exp.Array and dialect.HAS_DISTINCT_ARRAY_CONSTRUCTORS:
128        array_exp.set("bracket_notation", bracket_kind == TokenType.L_BRACKET)
129
130    return array_exp
def build_convert_timezone( args: List, default_source_tz: Optional[str] = None) -> Union[sqlglot.expressions.ConvertTimezone, sqlglot.expressions.Anonymous]:
133def build_convert_timezone(
134    args: t.List, default_source_tz: t.Optional[str] = None
135) -> t.Union[exp.ConvertTimezone, exp.Anonymous]:
136    if len(args) == 2:
137        source_tz = exp.Literal.string(default_source_tz) if default_source_tz else None
138        return exp.ConvertTimezone(
139            source_tz=source_tz, target_tz=seq_get(args, 0), timestamp=seq_get(args, 1)
140        )
141
142    return exp.ConvertTimezone.from_arg_list(args)
def build_trim(args: List, is_left: bool = True):
145def build_trim(args: t.List, is_left: bool = True):
146    return exp.Trim(
147        this=seq_get(args, 0),
148        expression=seq_get(args, 1),
149        position="LEADING" if is_left else "TRAILING",
150    )
def build_coalesce( args: List, is_nvl: Optional[bool] = None) -> sqlglot.expressions.Coalesce:
153def build_coalesce(args: t.List, is_nvl: t.Optional[bool] = None) -> exp.Coalesce:
154    return exp.Coalesce(this=seq_get(args, 0), expressions=args[1:], is_nvl=is_nvl)
def build_locate_strposition(args: List):
157def build_locate_strposition(args: t.List):
158    return exp.StrPosition(
159        this=seq_get(args, 1),
160        substr=seq_get(args, 0),
161        position=seq_get(args, 2),
162    )
class Parser:
 175class Parser(metaclass=_Parser):
 176    """
 177    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
 178
 179    Args:
 180        error_level: The desired error level.
 181            Default: ErrorLevel.IMMEDIATE
 182        error_message_context: The amount of context to capture from a query string when displaying
 183            the error message (in number of characters).
 184            Default: 100
 185        max_errors: Maximum number of error messages to include in a raised ParseError.
 186            This is only relevant if error_level is ErrorLevel.RAISE.
 187            Default: 3
 188    """
 189
 190    FUNCTIONS: t.Dict[str, t.Callable] = {
 191        **{name: func.from_arg_list for name, func in exp.FUNCTION_BY_NAME.items()},
 192        **dict.fromkeys(("COALESCE", "IFNULL", "NVL"), build_coalesce),
 193        "ARRAY": lambda args, dialect: exp.Array(expressions=args),
 194        "ARRAYAGG": lambda args, dialect: exp.ArrayAgg(
 195            this=seq_get(args, 0), nulls_excluded=dialect.ARRAY_AGG_INCLUDES_NULLS is None or None
 196        ),
 197        "ARRAY_AGG": lambda args, dialect: exp.ArrayAgg(
 198            this=seq_get(args, 0), nulls_excluded=dialect.ARRAY_AGG_INCLUDES_NULLS is None or None
 199        ),
 200        "CHAR": lambda args: exp.Chr(expressions=args),
 201        "CHR": lambda args: exp.Chr(expressions=args),
 202        "COUNT": lambda args: exp.Count(this=seq_get(args, 0), expressions=args[1:], big_int=True),
 203        "CONCAT": lambda args, dialect: exp.Concat(
 204            expressions=args,
 205            safe=not dialect.STRICT_STRING_CONCAT,
 206            coalesce=dialect.CONCAT_COALESCE,
 207        ),
 208        "CONCAT_WS": lambda args, dialect: exp.ConcatWs(
 209            expressions=args,
 210            safe=not dialect.STRICT_STRING_CONCAT,
 211            coalesce=dialect.CONCAT_COALESCE,
 212        ),
 213        "CONVERT_TIMEZONE": build_convert_timezone,
 214        "DATE_TO_DATE_STR": lambda args: exp.Cast(
 215            this=seq_get(args, 0),
 216            to=exp.DataType(this=exp.DataType.Type.TEXT),
 217        ),
 218        "GENERATE_DATE_ARRAY": lambda args: exp.GenerateDateArray(
 219            start=seq_get(args, 0),
 220            end=seq_get(args, 1),
 221            step=seq_get(args, 2) or exp.Interval(this=exp.Literal.number(1), unit=exp.var("DAY")),
 222        ),
 223        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
 224        "HEX": build_hex,
 225        "JSON_EXTRACT": build_extract_json_with_path(exp.JSONExtract),
 226        "JSON_EXTRACT_SCALAR": build_extract_json_with_path(exp.JSONExtractScalar),
 227        "JSON_EXTRACT_PATH_TEXT": build_extract_json_with_path(exp.JSONExtractScalar),
 228        "LIKE": build_like,
 229        "LOG": build_logarithm,
 230        "LOG2": lambda args: exp.Log(this=exp.Literal.number(2), expression=seq_get(args, 0)),
 231        "LOG10": lambda args: exp.Log(this=exp.Literal.number(10), expression=seq_get(args, 0)),
 232        "LOWER": build_lower,
 233        "LPAD": lambda args: build_pad(args),
 234        "LEFTPAD": lambda args: build_pad(args),
 235        "LTRIM": lambda args: build_trim(args),
 236        "MOD": build_mod,
 237        "RIGHTPAD": lambda args: build_pad(args, is_left=False),
 238        "RPAD": lambda args: build_pad(args, is_left=False),
 239        "RTRIM": lambda args: build_trim(args, is_left=False),
 240        "SCOPE_RESOLUTION": lambda args: exp.ScopeResolution(expression=seq_get(args, 0))
 241        if len(args) != 2
 242        else exp.ScopeResolution(this=seq_get(args, 0), expression=seq_get(args, 1)),
 243        "STRPOS": exp.StrPosition.from_arg_list,
 244        "CHARINDEX": lambda args: build_locate_strposition(args),
 245        "INSTR": exp.StrPosition.from_arg_list,
 246        "LOCATE": lambda args: build_locate_strposition(args),
 247        "TIME_TO_TIME_STR": lambda args: exp.Cast(
 248            this=seq_get(args, 0),
 249            to=exp.DataType(this=exp.DataType.Type.TEXT),
 250        ),
 251        "TO_HEX": build_hex,
 252        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
 253            this=exp.Cast(
 254                this=seq_get(args, 0),
 255                to=exp.DataType(this=exp.DataType.Type.TEXT),
 256            ),
 257            start=exp.Literal.number(1),
 258            length=exp.Literal.number(10),
 259        ),
 260        "UNNEST": lambda args: exp.Unnest(expressions=ensure_list(seq_get(args, 0))),
 261        "UPPER": build_upper,
 262        "VAR_MAP": build_var_map,
 263    }
 264
 265    NO_PAREN_FUNCTIONS = {
 266        TokenType.CURRENT_DATE: exp.CurrentDate,
 267        TokenType.CURRENT_DATETIME: exp.CurrentDate,
 268        TokenType.CURRENT_TIME: exp.CurrentTime,
 269        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
 270        TokenType.CURRENT_USER: exp.CurrentUser,
 271    }
 272
 273    STRUCT_TYPE_TOKENS = {
 274        TokenType.NESTED,
 275        TokenType.OBJECT,
 276        TokenType.STRUCT,
 277        TokenType.UNION,
 278    }
 279
 280    NESTED_TYPE_TOKENS = {
 281        TokenType.ARRAY,
 282        TokenType.LIST,
 283        TokenType.LOWCARDINALITY,
 284        TokenType.MAP,
 285        TokenType.NULLABLE,
 286        TokenType.RANGE,
 287        *STRUCT_TYPE_TOKENS,
 288    }
 289
 290    ENUM_TYPE_TOKENS = {
 291        TokenType.DYNAMIC,
 292        TokenType.ENUM,
 293        TokenType.ENUM8,
 294        TokenType.ENUM16,
 295    }
 296
 297    AGGREGATE_TYPE_TOKENS = {
 298        TokenType.AGGREGATEFUNCTION,
 299        TokenType.SIMPLEAGGREGATEFUNCTION,
 300    }
 301
 302    TYPE_TOKENS = {
 303        TokenType.BIT,
 304        TokenType.BOOLEAN,
 305        TokenType.TINYINT,
 306        TokenType.UTINYINT,
 307        TokenType.SMALLINT,
 308        TokenType.USMALLINT,
 309        TokenType.INT,
 310        TokenType.UINT,
 311        TokenType.BIGINT,
 312        TokenType.UBIGINT,
 313        TokenType.INT128,
 314        TokenType.UINT128,
 315        TokenType.INT256,
 316        TokenType.UINT256,
 317        TokenType.MEDIUMINT,
 318        TokenType.UMEDIUMINT,
 319        TokenType.FIXEDSTRING,
 320        TokenType.FLOAT,
 321        TokenType.DOUBLE,
 322        TokenType.CHAR,
 323        TokenType.NCHAR,
 324        TokenType.VARCHAR,
 325        TokenType.NVARCHAR,
 326        TokenType.BPCHAR,
 327        TokenType.TEXT,
 328        TokenType.MEDIUMTEXT,
 329        TokenType.LONGTEXT,
 330        TokenType.MEDIUMBLOB,
 331        TokenType.LONGBLOB,
 332        TokenType.BINARY,
 333        TokenType.VARBINARY,
 334        TokenType.JSON,
 335        TokenType.JSONB,
 336        TokenType.INTERVAL,
 337        TokenType.TINYBLOB,
 338        TokenType.TINYTEXT,
 339        TokenType.TIME,
 340        TokenType.TIMETZ,
 341        TokenType.TIMESTAMP,
 342        TokenType.TIMESTAMP_S,
 343        TokenType.TIMESTAMP_MS,
 344        TokenType.TIMESTAMP_NS,
 345        TokenType.TIMESTAMPTZ,
 346        TokenType.TIMESTAMPLTZ,
 347        TokenType.TIMESTAMPNTZ,
 348        TokenType.DATETIME,
 349        TokenType.DATETIME2,
 350        TokenType.DATETIME64,
 351        TokenType.SMALLDATETIME,
 352        TokenType.DATE,
 353        TokenType.DATE32,
 354        TokenType.INT4RANGE,
 355        TokenType.INT4MULTIRANGE,
 356        TokenType.INT8RANGE,
 357        TokenType.INT8MULTIRANGE,
 358        TokenType.NUMRANGE,
 359        TokenType.NUMMULTIRANGE,
 360        TokenType.TSRANGE,
 361        TokenType.TSMULTIRANGE,
 362        TokenType.TSTZRANGE,
 363        TokenType.TSTZMULTIRANGE,
 364        TokenType.DATERANGE,
 365        TokenType.DATEMULTIRANGE,
 366        TokenType.DECIMAL,
 367        TokenType.DECIMAL32,
 368        TokenType.DECIMAL64,
 369        TokenType.DECIMAL128,
 370        TokenType.DECIMAL256,
 371        TokenType.UDECIMAL,
 372        TokenType.BIGDECIMAL,
 373        TokenType.UUID,
 374        TokenType.GEOGRAPHY,
 375        TokenType.GEOMETRY,
 376        TokenType.POINT,
 377        TokenType.RING,
 378        TokenType.LINESTRING,
 379        TokenType.MULTILINESTRING,
 380        TokenType.POLYGON,
 381        TokenType.MULTIPOLYGON,
 382        TokenType.HLLSKETCH,
 383        TokenType.HSTORE,
 384        TokenType.PSEUDO_TYPE,
 385        TokenType.SUPER,
 386        TokenType.SERIAL,
 387        TokenType.SMALLSERIAL,
 388        TokenType.BIGSERIAL,
 389        TokenType.XML,
 390        TokenType.YEAR,
 391        TokenType.UNIQUEIDENTIFIER,
 392        TokenType.USERDEFINED,
 393        TokenType.MONEY,
 394        TokenType.SMALLMONEY,
 395        TokenType.ROWVERSION,
 396        TokenType.IMAGE,
 397        TokenType.VARIANT,
 398        TokenType.VECTOR,
 399        TokenType.OBJECT,
 400        TokenType.OBJECT_IDENTIFIER,
 401        TokenType.INET,
 402        TokenType.IPADDRESS,
 403        TokenType.IPPREFIX,
 404        TokenType.IPV4,
 405        TokenType.IPV6,
 406        TokenType.UNKNOWN,
 407        TokenType.NULL,
 408        TokenType.NAME,
 409        TokenType.TDIGEST,
 410        TokenType.DYNAMIC,
 411        *ENUM_TYPE_TOKENS,
 412        *NESTED_TYPE_TOKENS,
 413        *AGGREGATE_TYPE_TOKENS,
 414    }
 415
 416    SIGNED_TO_UNSIGNED_TYPE_TOKEN = {
 417        TokenType.BIGINT: TokenType.UBIGINT,
 418        TokenType.INT: TokenType.UINT,
 419        TokenType.MEDIUMINT: TokenType.UMEDIUMINT,
 420        TokenType.SMALLINT: TokenType.USMALLINT,
 421        TokenType.TINYINT: TokenType.UTINYINT,
 422        TokenType.DECIMAL: TokenType.UDECIMAL,
 423    }
 424
 425    SUBQUERY_PREDICATES = {
 426        TokenType.ANY: exp.Any,
 427        TokenType.ALL: exp.All,
 428        TokenType.EXISTS: exp.Exists,
 429        TokenType.SOME: exp.Any,
 430    }
 431
 432    RESERVED_TOKENS = {
 433        *Tokenizer.SINGLE_TOKENS.values(),
 434        TokenType.SELECT,
 435    } - {TokenType.IDENTIFIER}
 436
 437    DB_CREATABLES = {
 438        TokenType.DATABASE,
 439        TokenType.DICTIONARY,
 440        TokenType.MODEL,
 441        TokenType.NAMESPACE,
 442        TokenType.SCHEMA,
 443        TokenType.SEQUENCE,
 444        TokenType.SINK,
 445        TokenType.SOURCE,
 446        TokenType.STORAGE_INTEGRATION,
 447        TokenType.STREAMLIT,
 448        TokenType.TABLE,
 449        TokenType.TAG,
 450        TokenType.VIEW,
 451        TokenType.WAREHOUSE,
 452    }
 453
 454    CREATABLES = {
 455        TokenType.COLUMN,
 456        TokenType.CONSTRAINT,
 457        TokenType.FOREIGN_KEY,
 458        TokenType.FUNCTION,
 459        TokenType.INDEX,
 460        TokenType.PROCEDURE,
 461        *DB_CREATABLES,
 462    }
 463
 464    ALTERABLES = {
 465        TokenType.INDEX,
 466        TokenType.TABLE,
 467        TokenType.VIEW,
 468    }
 469
 470    # Tokens that can represent identifiers
 471    ID_VAR_TOKENS = {
 472        TokenType.ALL,
 473        TokenType.ATTACH,
 474        TokenType.VAR,
 475        TokenType.ANTI,
 476        TokenType.APPLY,
 477        TokenType.ASC,
 478        TokenType.ASOF,
 479        TokenType.AUTO_INCREMENT,
 480        TokenType.BEGIN,
 481        TokenType.BPCHAR,
 482        TokenType.CACHE,
 483        TokenType.CASE,
 484        TokenType.COLLATE,
 485        TokenType.COMMAND,
 486        TokenType.COMMENT,
 487        TokenType.COMMIT,
 488        TokenType.CONSTRAINT,
 489        TokenType.COPY,
 490        TokenType.CUBE,
 491        TokenType.DEFAULT,
 492        TokenType.DELETE,
 493        TokenType.DESC,
 494        TokenType.DESCRIBE,
 495        TokenType.DETACH,
 496        TokenType.DICTIONARY,
 497        TokenType.DIV,
 498        TokenType.END,
 499        TokenType.EXECUTE,
 500        TokenType.ESCAPE,
 501        TokenType.FALSE,
 502        TokenType.FIRST,
 503        TokenType.FILTER,
 504        TokenType.FINAL,
 505        TokenType.FORMAT,
 506        TokenType.FULL,
 507        TokenType.IDENTIFIER,
 508        TokenType.IS,
 509        TokenType.ISNULL,
 510        TokenType.INTERVAL,
 511        TokenType.KEEP,
 512        TokenType.KILL,
 513        TokenType.LEFT,
 514        TokenType.LIMIT,
 515        TokenType.LOAD,
 516        TokenType.MERGE,
 517        TokenType.NATURAL,
 518        TokenType.NEXT,
 519        TokenType.OFFSET,
 520        TokenType.OPERATOR,
 521        TokenType.ORDINALITY,
 522        TokenType.OVERLAPS,
 523        TokenType.OVERWRITE,
 524        TokenType.PARTITION,
 525        TokenType.PERCENT,
 526        TokenType.PIVOT,
 527        TokenType.PRAGMA,
 528        TokenType.RANGE,
 529        TokenType.RECURSIVE,
 530        TokenType.REFERENCES,
 531        TokenType.REFRESH,
 532        TokenType.RENAME,
 533        TokenType.REPLACE,
 534        TokenType.RIGHT,
 535        TokenType.ROLLUP,
 536        TokenType.ROW,
 537        TokenType.ROWS,
 538        TokenType.SEMI,
 539        TokenType.SET,
 540        TokenType.SETTINGS,
 541        TokenType.SHOW,
 542        TokenType.TEMPORARY,
 543        TokenType.TOP,
 544        TokenType.TRUE,
 545        TokenType.TRUNCATE,
 546        TokenType.UNIQUE,
 547        TokenType.UNNEST,
 548        TokenType.UNPIVOT,
 549        TokenType.UPDATE,
 550        TokenType.USE,
 551        TokenType.VOLATILE,
 552        TokenType.WINDOW,
 553        *CREATABLES,
 554        *SUBQUERY_PREDICATES,
 555        *TYPE_TOKENS,
 556        *NO_PAREN_FUNCTIONS,
 557    }
 558    ID_VAR_TOKENS.remove(TokenType.UNION)
 559
 560    INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
 561
 562    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
 563        TokenType.ANTI,
 564        TokenType.APPLY,
 565        TokenType.ASOF,
 566        TokenType.FULL,
 567        TokenType.LEFT,
 568        TokenType.LOCK,
 569        TokenType.NATURAL,
 570        TokenType.RIGHT,
 571        TokenType.SEMI,
 572        TokenType.WINDOW,
 573    }
 574
 575    ALIAS_TOKENS = ID_VAR_TOKENS
 576
 577    ARRAY_CONSTRUCTORS = {
 578        "ARRAY": exp.Array,
 579        "LIST": exp.List,
 580    }
 581
 582    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
 583
 584    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
 585
 586    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
 587
 588    FUNC_TOKENS = {
 589        TokenType.COLLATE,
 590        TokenType.COMMAND,
 591        TokenType.CURRENT_DATE,
 592        TokenType.CURRENT_DATETIME,
 593        TokenType.CURRENT_TIMESTAMP,
 594        TokenType.CURRENT_TIME,
 595        TokenType.CURRENT_USER,
 596        TokenType.FILTER,
 597        TokenType.FIRST,
 598        TokenType.FORMAT,
 599        TokenType.GLOB,
 600        TokenType.IDENTIFIER,
 601        TokenType.INDEX,
 602        TokenType.ISNULL,
 603        TokenType.ILIKE,
 604        TokenType.INSERT,
 605        TokenType.LIKE,
 606        TokenType.MERGE,
 607        TokenType.NEXT,
 608        TokenType.OFFSET,
 609        TokenType.PRIMARY_KEY,
 610        TokenType.RANGE,
 611        TokenType.REPLACE,
 612        TokenType.RLIKE,
 613        TokenType.ROW,
 614        TokenType.UNNEST,
 615        TokenType.VAR,
 616        TokenType.LEFT,
 617        TokenType.RIGHT,
 618        TokenType.SEQUENCE,
 619        TokenType.DATE,
 620        TokenType.DATETIME,
 621        TokenType.TABLE,
 622        TokenType.TIMESTAMP,
 623        TokenType.TIMESTAMPTZ,
 624        TokenType.TRUNCATE,
 625        TokenType.WINDOW,
 626        TokenType.XOR,
 627        *TYPE_TOKENS,
 628        *SUBQUERY_PREDICATES,
 629    }
 630
 631    CONJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
 632        TokenType.AND: exp.And,
 633    }
 634
 635    ASSIGNMENT: t.Dict[TokenType, t.Type[exp.Expression]] = {
 636        TokenType.COLON_EQ: exp.PropertyEQ,
 637    }
 638
 639    DISJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
 640        TokenType.OR: exp.Or,
 641    }
 642
 643    EQUALITY = {
 644        TokenType.EQ: exp.EQ,
 645        TokenType.NEQ: exp.NEQ,
 646        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
 647    }
 648
 649    COMPARISON = {
 650        TokenType.GT: exp.GT,
 651        TokenType.GTE: exp.GTE,
 652        TokenType.LT: exp.LT,
 653        TokenType.LTE: exp.LTE,
 654    }
 655
 656    BITWISE = {
 657        TokenType.AMP: exp.BitwiseAnd,
 658        TokenType.CARET: exp.BitwiseXor,
 659        TokenType.PIPE: exp.BitwiseOr,
 660    }
 661
 662    TERM = {
 663        TokenType.DASH: exp.Sub,
 664        TokenType.PLUS: exp.Add,
 665        TokenType.MOD: exp.Mod,
 666        TokenType.COLLATE: exp.Collate,
 667    }
 668
 669    FACTOR = {
 670        TokenType.DIV: exp.IntDiv,
 671        TokenType.LR_ARROW: exp.Distance,
 672        TokenType.SLASH: exp.Div,
 673        TokenType.STAR: exp.Mul,
 674    }
 675
 676    EXPONENT: t.Dict[TokenType, t.Type[exp.Expression]] = {}
 677
 678    TIMES = {
 679        TokenType.TIME,
 680        TokenType.TIMETZ,
 681    }
 682
 683    TIMESTAMPS = {
 684        TokenType.TIMESTAMP,
 685        TokenType.TIMESTAMPTZ,
 686        TokenType.TIMESTAMPLTZ,
 687        *TIMES,
 688    }
 689
 690    SET_OPERATIONS = {
 691        TokenType.UNION,
 692        TokenType.INTERSECT,
 693        TokenType.EXCEPT,
 694    }
 695
 696    JOIN_METHODS = {
 697        TokenType.ASOF,
 698        TokenType.NATURAL,
 699        TokenType.POSITIONAL,
 700    }
 701
 702    JOIN_SIDES = {
 703        TokenType.LEFT,
 704        TokenType.RIGHT,
 705        TokenType.FULL,
 706    }
 707
 708    JOIN_KINDS = {
 709        TokenType.ANTI,
 710        TokenType.CROSS,
 711        TokenType.INNER,
 712        TokenType.OUTER,
 713        TokenType.SEMI,
 714        TokenType.STRAIGHT_JOIN,
 715    }
 716
 717    JOIN_HINTS: t.Set[str] = set()
 718
 719    LAMBDAS = {
 720        TokenType.ARROW: lambda self, expressions: self.expression(
 721            exp.Lambda,
 722            this=self._replace_lambda(
 723                self._parse_assignment(),
 724                expressions,
 725            ),
 726            expressions=expressions,
 727        ),
 728        TokenType.FARROW: lambda self, expressions: self.expression(
 729            exp.Kwarg,
 730            this=exp.var(expressions[0].name),
 731            expression=self._parse_assignment(),
 732        ),
 733    }
 734
 735    COLUMN_OPERATORS = {
 736        TokenType.DOT: None,
 737        TokenType.DCOLON: lambda self, this, to: self.expression(
 738            exp.Cast if self.STRICT_CAST else exp.TryCast,
 739            this=this,
 740            to=to,
 741        ),
 742        TokenType.ARROW: lambda self, this, path: self.expression(
 743            exp.JSONExtract,
 744            this=this,
 745            expression=self.dialect.to_json_path(path),
 746            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
 747        ),
 748        TokenType.DARROW: lambda self, this, path: self.expression(
 749            exp.JSONExtractScalar,
 750            this=this,
 751            expression=self.dialect.to_json_path(path),
 752            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
 753        ),
 754        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
 755            exp.JSONBExtract,
 756            this=this,
 757            expression=path,
 758        ),
 759        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
 760            exp.JSONBExtractScalar,
 761            this=this,
 762            expression=path,
 763        ),
 764        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
 765            exp.JSONBContains,
 766            this=this,
 767            expression=key,
 768        ),
 769    }
 770
 771    EXPRESSION_PARSERS = {
 772        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
 773        exp.Column: lambda self: self._parse_column(),
 774        exp.Condition: lambda self: self._parse_assignment(),
 775        exp.DataType: lambda self: self._parse_types(allow_identifiers=False, schema=True),
 776        exp.Expression: lambda self: self._parse_expression(),
 777        exp.From: lambda self: self._parse_from(joins=True),
 778        exp.Group: lambda self: self._parse_group(),
 779        exp.Having: lambda self: self._parse_having(),
 780        exp.Hint: lambda self: self._parse_hint_body(),
 781        exp.Identifier: lambda self: self._parse_id_var(),
 782        exp.Join: lambda self: self._parse_join(),
 783        exp.Lambda: lambda self: self._parse_lambda(),
 784        exp.Lateral: lambda self: self._parse_lateral(),
 785        exp.Limit: lambda self: self._parse_limit(),
 786        exp.Offset: lambda self: self._parse_offset(),
 787        exp.Order: lambda self: self._parse_order(),
 788        exp.Ordered: lambda self: self._parse_ordered(),
 789        exp.Properties: lambda self: self._parse_properties(),
 790        exp.Qualify: lambda self: self._parse_qualify(),
 791        exp.Returning: lambda self: self._parse_returning(),
 792        exp.Select: lambda self: self._parse_select(),
 793        exp.Sort: lambda self: self._parse_sort(exp.Sort, TokenType.SORT_BY),
 794        exp.Table: lambda self: self._parse_table_parts(),
 795        exp.TableAlias: lambda self: self._parse_table_alias(),
 796        exp.Tuple: lambda self: self._parse_value(),
 797        exp.Whens: lambda self: self._parse_when_matched(),
 798        exp.Where: lambda self: self._parse_where(),
 799        exp.Window: lambda self: self._parse_named_window(),
 800        exp.With: lambda self: self._parse_with(),
 801        "JOIN_TYPE": lambda self: self._parse_join_parts(),
 802    }
 803
 804    STATEMENT_PARSERS = {
 805        TokenType.ALTER: lambda self: self._parse_alter(),
 806        TokenType.ANALYZE: lambda self: self._parse_analyze(),
 807        TokenType.BEGIN: lambda self: self._parse_transaction(),
 808        TokenType.CACHE: lambda self: self._parse_cache(),
 809        TokenType.COMMENT: lambda self: self._parse_comment(),
 810        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
 811        TokenType.COPY: lambda self: self._parse_copy(),
 812        TokenType.CREATE: lambda self: self._parse_create(),
 813        TokenType.DELETE: lambda self: self._parse_delete(),
 814        TokenType.DESC: lambda self: self._parse_describe(),
 815        TokenType.DESCRIBE: lambda self: self._parse_describe(),
 816        TokenType.DROP: lambda self: self._parse_drop(),
 817        TokenType.GRANT: lambda self: self._parse_grant(),
 818        TokenType.INSERT: lambda self: self._parse_insert(),
 819        TokenType.KILL: lambda self: self._parse_kill(),
 820        TokenType.LOAD: lambda self: self._parse_load(),
 821        TokenType.MERGE: lambda self: self._parse_merge(),
 822        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
 823        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
 824        TokenType.REFRESH: lambda self: self._parse_refresh(),
 825        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
 826        TokenType.SET: lambda self: self._parse_set(),
 827        TokenType.TRUNCATE: lambda self: self._parse_truncate_table(),
 828        TokenType.UNCACHE: lambda self: self._parse_uncache(),
 829        TokenType.UNPIVOT: lambda self: self._parse_simplified_pivot(is_unpivot=True),
 830        TokenType.UPDATE: lambda self: self._parse_update(),
 831        TokenType.USE: lambda self: self.expression(
 832            exp.Use,
 833            kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
 834            this=self._parse_table(schema=False),
 835        ),
 836        TokenType.SEMICOLON: lambda self: exp.Semicolon(),
 837    }
 838
 839    UNARY_PARSERS = {
 840        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
 841        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
 842        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
 843        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
 844        TokenType.PIPE_SLASH: lambda self: self.expression(exp.Sqrt, this=self._parse_unary()),
 845        TokenType.DPIPE_SLASH: lambda self: self.expression(exp.Cbrt, this=self._parse_unary()),
 846    }
 847
 848    STRING_PARSERS = {
 849        TokenType.HEREDOC_STRING: lambda self, token: self.expression(
 850            exp.RawString, this=token.text
 851        ),
 852        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
 853            exp.National, this=token.text
 854        ),
 855        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
 856        TokenType.STRING: lambda self, token: self.expression(
 857            exp.Literal, this=token.text, is_string=True
 858        ),
 859        TokenType.UNICODE_STRING: lambda self, token: self.expression(
 860            exp.UnicodeString,
 861            this=token.text,
 862            escape=self._match_text_seq("UESCAPE") and self._parse_string(),
 863        ),
 864    }
 865
 866    NUMERIC_PARSERS = {
 867        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
 868        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
 869        TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text),
 870        TokenType.NUMBER: lambda self, token: self.expression(
 871            exp.Literal, this=token.text, is_string=False
 872        ),
 873    }
 874
 875    PRIMARY_PARSERS = {
 876        **STRING_PARSERS,
 877        **NUMERIC_PARSERS,
 878        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
 879        TokenType.NULL: lambda self, _: self.expression(exp.Null),
 880        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
 881        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
 882        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
 883        TokenType.STAR: lambda self, _: self._parse_star_ops(),
 884    }
 885
 886    PLACEHOLDER_PARSERS = {
 887        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
 888        TokenType.PARAMETER: lambda self: self._parse_parameter(),
 889        TokenType.COLON: lambda self: (
 890            self.expression(exp.Placeholder, this=self._prev.text)
 891            if self._match_set(self.ID_VAR_TOKENS)
 892            else None
 893        ),
 894    }
 895
 896    RANGE_PARSERS = {
 897        TokenType.AT_GT: binary_range_parser(exp.ArrayContainsAll),
 898        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
 899        TokenType.GLOB: binary_range_parser(exp.Glob),
 900        TokenType.ILIKE: binary_range_parser(exp.ILike),
 901        TokenType.IN: lambda self, this: self._parse_in(this),
 902        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
 903        TokenType.IS: lambda self, this: self._parse_is(this),
 904        TokenType.LIKE: binary_range_parser(exp.Like),
 905        TokenType.LT_AT: binary_range_parser(exp.ArrayContainsAll, reverse_args=True),
 906        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
 907        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
 908        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
 909        TokenType.FOR: lambda self, this: self._parse_comprehension(this),
 910    }
 911
 912    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
 913        "ALLOWED_VALUES": lambda self: self.expression(
 914            exp.AllowedValuesProperty, expressions=self._parse_csv(self._parse_primary)
 915        ),
 916        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
 917        "AUTO": lambda self: self._parse_auto_property(),
 918        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
 919        "BACKUP": lambda self: self.expression(
 920            exp.BackupProperty, this=self._parse_var(any_token=True)
 921        ),
 922        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
 923        "CHARSET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 924        "CHARACTER SET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 925        "CHECKSUM": lambda self: self._parse_checksum(),
 926        "CLUSTER BY": lambda self: self._parse_cluster(),
 927        "CLUSTERED": lambda self: self._parse_clustered_by(),
 928        "COLLATE": lambda self, **kwargs: self._parse_property_assignment(
 929            exp.CollateProperty, **kwargs
 930        ),
 931        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
 932        "CONTAINS": lambda self: self._parse_contains_property(),
 933        "COPY": lambda self: self._parse_copy_property(),
 934        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
 935        "DATA_DELETION": lambda self: self._parse_data_deletion_property(),
 936        "DEFINER": lambda self: self._parse_definer(),
 937        "DETERMINISTIC": lambda self: self.expression(
 938            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 939        ),
 940        "DISTRIBUTED": lambda self: self._parse_distributed_property(),
 941        "DUPLICATE": lambda self: self._parse_composite_key_property(exp.DuplicateKeyProperty),
 942        "DYNAMIC": lambda self: self.expression(exp.DynamicProperty),
 943        "DISTKEY": lambda self: self._parse_distkey(),
 944        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
 945        "EMPTY": lambda self: self.expression(exp.EmptyProperty),
 946        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
 947        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
 948        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
 949        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
 950        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 951        "FREESPACE": lambda self: self._parse_freespace(),
 952        "GLOBAL": lambda self: self.expression(exp.GlobalProperty),
 953        "HEAP": lambda self: self.expression(exp.HeapProperty),
 954        "ICEBERG": lambda self: self.expression(exp.IcebergProperty),
 955        "IMMUTABLE": lambda self: self.expression(
 956            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 957        ),
 958        "INHERITS": lambda self: self.expression(
 959            exp.InheritsProperty, expressions=self._parse_wrapped_csv(self._parse_table)
 960        ),
 961        "INPUT": lambda self: self.expression(exp.InputModelProperty, this=self._parse_schema()),
 962        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
 963        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
 964        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
 965        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
 966        "LIKE": lambda self: self._parse_create_like(),
 967        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
 968        "LOCK": lambda self: self._parse_locking(),
 969        "LOCKING": lambda self: self._parse_locking(),
 970        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
 971        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
 972        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
 973        "MODIFIES": lambda self: self._parse_modifies_property(),
 974        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
 975        "NO": lambda self: self._parse_no_property(),
 976        "ON": lambda self: self._parse_on_property(),
 977        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
 978        "OUTPUT": lambda self: self.expression(exp.OutputModelProperty, this=self._parse_schema()),
 979        "PARTITION": lambda self: self._parse_partitioned_of(),
 980        "PARTITION BY": lambda self: self._parse_partitioned_by(),
 981        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
 982        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
 983        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
 984        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
 985        "READS": lambda self: self._parse_reads_property(),
 986        "REMOTE": lambda self: self._parse_remote_with_connection(),
 987        "RETURNS": lambda self: self._parse_returns(),
 988        "STRICT": lambda self: self.expression(exp.StrictProperty),
 989        "STREAMING": lambda self: self.expression(exp.StreamingTableProperty),
 990        "ROW": lambda self: self._parse_row(),
 991        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
 992        "SAMPLE": lambda self: self.expression(
 993            exp.SampleProperty, this=self._match_text_seq("BY") and self._parse_bitwise()
 994        ),
 995        "SECURE": lambda self: self.expression(exp.SecureProperty),
 996        "SECURITY": lambda self: self._parse_security(),
 997        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
 998        "SETTINGS": lambda self: self._parse_settings_property(),
 999        "SHARING": lambda self: self._parse_property_assignment(exp.SharingProperty),
1000        "SORTKEY": lambda self: self._parse_sortkey(),
1001        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
1002        "STABLE": lambda self: self.expression(
1003            exp.StabilityProperty, this=exp.Literal.string("STABLE")
1004        ),
1005        "STORED": lambda self: self._parse_stored(),
1006        "SYSTEM_VERSIONING": lambda self: self._parse_system_versioning_property(),
1007        "TBLPROPERTIES": lambda self: self._parse_wrapped_properties(),
1008        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
1009        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
1010        "TO": lambda self: self._parse_to_table(),
1011        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
1012        "TRANSFORM": lambda self: self.expression(
1013            exp.TransformModelProperty, expressions=self._parse_wrapped_csv(self._parse_expression)
1014        ),
1015        "TTL": lambda self: self._parse_ttl(),
1016        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
1017        "UNLOGGED": lambda self: self.expression(exp.UnloggedProperty),
1018        "VOLATILE": lambda self: self._parse_volatile_property(),
1019        "WITH": lambda self: self._parse_with_property(),
1020    }
1021
1022    CONSTRAINT_PARSERS = {
1023        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
1024        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
1025        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
1026        "CHARACTER SET": lambda self: self.expression(
1027            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
1028        ),
1029        "CHECK": lambda self: self.expression(
1030            exp.CheckColumnConstraint,
1031            this=self._parse_wrapped(self._parse_assignment),
1032            enforced=self._match_text_seq("ENFORCED"),
1033        ),
1034        "COLLATE": lambda self: self.expression(
1035            exp.CollateColumnConstraint,
1036            this=self._parse_identifier() or self._parse_column(),
1037        ),
1038        "COMMENT": lambda self: self.expression(
1039            exp.CommentColumnConstraint, this=self._parse_string()
1040        ),
1041        "COMPRESS": lambda self: self._parse_compress(),
1042        "CLUSTERED": lambda self: self.expression(
1043            exp.ClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
1044        ),
1045        "NONCLUSTERED": lambda self: self.expression(
1046            exp.NonClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
1047        ),
1048        "DEFAULT": lambda self: self.expression(
1049            exp.DefaultColumnConstraint, this=self._parse_bitwise()
1050        ),
1051        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
1052        "EPHEMERAL": lambda self: self.expression(
1053            exp.EphemeralColumnConstraint, this=self._parse_bitwise()
1054        ),
1055        "EXCLUDE": lambda self: self.expression(
1056            exp.ExcludeColumnConstraint, this=self._parse_index_params()
1057        ),
1058        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
1059        "FORMAT": lambda self: self.expression(
1060            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
1061        ),
1062        "GENERATED": lambda self: self._parse_generated_as_identity(),
1063        "IDENTITY": lambda self: self._parse_auto_increment(),
1064        "INLINE": lambda self: self._parse_inline(),
1065        "LIKE": lambda self: self._parse_create_like(),
1066        "NOT": lambda self: self._parse_not_constraint(),
1067        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
1068        "ON": lambda self: (
1069            self._match(TokenType.UPDATE)
1070            and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function())
1071        )
1072        or self.expression(exp.OnProperty, this=self._parse_id_var()),
1073        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
1074        "PERIOD": lambda self: self._parse_period_for_system_time(),
1075        "PRIMARY KEY": lambda self: self._parse_primary_key(),
1076        "REFERENCES": lambda self: self._parse_references(match=False),
1077        "TITLE": lambda self: self.expression(
1078            exp.TitleColumnConstraint, this=self._parse_var_or_string()
1079        ),
1080        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
1081        "UNIQUE": lambda self: self._parse_unique(),
1082        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
1083        "WATERMARK": lambda self: self.expression(
1084            exp.WatermarkColumnConstraint,
1085            this=self._match(TokenType.FOR) and self._parse_column(),
1086            expression=self._match(TokenType.ALIAS) and self._parse_disjunction(),
1087        ),
1088        "WITH": lambda self: self.expression(
1089            exp.Properties, expressions=self._parse_wrapped_properties()
1090        ),
1091    }
1092
1093    ALTER_PARSERS = {
1094        "ADD": lambda self: self._parse_alter_table_add(),
1095        "AS": lambda self: self._parse_select(),
1096        "ALTER": lambda self: self._parse_alter_table_alter(),
1097        "CLUSTER BY": lambda self: self._parse_cluster(wrapped=True),
1098        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
1099        "DROP": lambda self: self._parse_alter_table_drop(),
1100        "RENAME": lambda self: self._parse_alter_table_rename(),
1101        "SET": lambda self: self._parse_alter_table_set(),
1102        "SWAP": lambda self: self.expression(
1103            exp.SwapTable, this=self._match(TokenType.WITH) and self._parse_table(schema=True)
1104        ),
1105    }
1106
1107    ALTER_ALTER_PARSERS = {
1108        "DISTKEY": lambda self: self._parse_alter_diststyle(),
1109        "DISTSTYLE": lambda self: self._parse_alter_diststyle(),
1110        "SORTKEY": lambda self: self._parse_alter_sortkey(),
1111        "COMPOUND": lambda self: self._parse_alter_sortkey(compound=True),
1112    }
1113
1114    SCHEMA_UNNAMED_CONSTRAINTS = {
1115        "CHECK",
1116        "EXCLUDE",
1117        "FOREIGN KEY",
1118        "LIKE",
1119        "PERIOD",
1120        "PRIMARY KEY",
1121        "UNIQUE",
1122        "WATERMARK",
1123    }
1124
1125    NO_PAREN_FUNCTION_PARSERS = {
1126        "ANY": lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
1127        "CASE": lambda self: self._parse_case(),
1128        "CONNECT_BY_ROOT": lambda self: self.expression(
1129            exp.ConnectByRoot, this=self._parse_column()
1130        ),
1131        "IF": lambda self: self._parse_if(),
1132    }
1133
1134    INVALID_FUNC_NAME_TOKENS = {
1135        TokenType.IDENTIFIER,
1136        TokenType.STRING,
1137    }
1138
1139    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
1140
1141    KEY_VALUE_DEFINITIONS = (exp.Alias, exp.EQ, exp.PropertyEQ, exp.Slice)
1142
1143    FUNCTION_PARSERS = {
1144        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
1145        "CEIL": lambda self: self._parse_ceil_floor(exp.Ceil),
1146        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
1147        "DECODE": lambda self: self._parse_decode(),
1148        "EXTRACT": lambda self: self._parse_extract(),
1149        "FLOOR": lambda self: self._parse_ceil_floor(exp.Floor),
1150        "GAP_FILL": lambda self: self._parse_gap_fill(),
1151        "JSON_OBJECT": lambda self: self._parse_json_object(),
1152        "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
1153        "JSON_TABLE": lambda self: self._parse_json_table(),
1154        "MATCH": lambda self: self._parse_match_against(),
1155        "NORMALIZE": lambda self: self._parse_normalize(),
1156        "OPENJSON": lambda self: self._parse_open_json(),
1157        "OVERLAY": lambda self: self._parse_overlay(),
1158        "POSITION": lambda self: self._parse_position(),
1159        "PREDICT": lambda self: self._parse_predict(),
1160        "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
1161        "STRING_AGG": lambda self: self._parse_string_agg(),
1162        "SUBSTRING": lambda self: self._parse_substring(),
1163        "TRIM": lambda self: self._parse_trim(),
1164        "TRY_CAST": lambda self: self._parse_cast(False, safe=True),
1165        "TRY_CONVERT": lambda self: self._parse_convert(False, safe=True),
1166        "XMLELEMENT": lambda self: self.expression(
1167            exp.XMLElement,
1168            this=self._match_text_seq("NAME") and self._parse_id_var(),
1169            expressions=self._match(TokenType.COMMA) and self._parse_csv(self._parse_expression),
1170        ),
1171        "XMLTABLE": lambda self: self._parse_xml_table(),
1172    }
1173
1174    QUERY_MODIFIER_PARSERS = {
1175        TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
1176        TokenType.PREWHERE: lambda self: ("prewhere", self._parse_prewhere()),
1177        TokenType.WHERE: lambda self: ("where", self._parse_where()),
1178        TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
1179        TokenType.HAVING: lambda self: ("having", self._parse_having()),
1180        TokenType.QUALIFY: lambda self: ("qualify", self._parse_qualify()),
1181        TokenType.WINDOW: lambda self: ("windows", self._parse_window_clause()),
1182        TokenType.ORDER_BY: lambda self: ("order", self._parse_order()),
1183        TokenType.LIMIT: lambda self: ("limit", self._parse_limit()),
1184        TokenType.FETCH: lambda self: ("limit", self._parse_limit()),
1185        TokenType.OFFSET: lambda self: ("offset", self._parse_offset()),
1186        TokenType.FOR: lambda self: ("locks", self._parse_locks()),
1187        TokenType.LOCK: lambda self: ("locks", self._parse_locks()),
1188        TokenType.TABLE_SAMPLE: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
1189        TokenType.USING: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
1190        TokenType.CLUSTER_BY: lambda self: (
1191            "cluster",
1192            self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
1193        ),
1194        TokenType.DISTRIBUTE_BY: lambda self: (
1195            "distribute",
1196            self._parse_sort(exp.Distribute, TokenType.DISTRIBUTE_BY),
1197        ),
1198        TokenType.SORT_BY: lambda self: ("sort", self._parse_sort(exp.Sort, TokenType.SORT_BY)),
1199        TokenType.CONNECT_BY: lambda self: ("connect", self._parse_connect(skip_start_token=True)),
1200        TokenType.START_WITH: lambda self: ("connect", self._parse_connect()),
1201    }
1202
1203    SET_PARSERS = {
1204        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
1205        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
1206        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
1207        "TRANSACTION": lambda self: self._parse_set_transaction(),
1208    }
1209
1210    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
1211
1212    TYPE_LITERAL_PARSERS = {
1213        exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
1214    }
1215
1216    TYPE_CONVERTERS: t.Dict[exp.DataType.Type, t.Callable[[exp.DataType], exp.DataType]] = {}
1217
1218    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
1219
1220    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
1221
1222    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
1223    TRANSACTION_CHARACTERISTICS: OPTIONS_TYPE = {
1224        "ISOLATION": (
1225            ("LEVEL", "REPEATABLE", "READ"),
1226            ("LEVEL", "READ", "COMMITTED"),
1227            ("LEVEL", "READ", "UNCOMITTED"),
1228            ("LEVEL", "SERIALIZABLE"),
1229        ),
1230        "READ": ("WRITE", "ONLY"),
1231    }
1232
1233    CONFLICT_ACTIONS: OPTIONS_TYPE = dict.fromkeys(
1234        ("ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK", "UPDATE"), tuple()
1235    )
1236    CONFLICT_ACTIONS["DO"] = ("NOTHING", "UPDATE")
1237
1238    CREATE_SEQUENCE: OPTIONS_TYPE = {
1239        "SCALE": ("EXTEND", "NOEXTEND"),
1240        "SHARD": ("EXTEND", "NOEXTEND"),
1241        "NO": ("CYCLE", "CACHE", "MAXVALUE", "MINVALUE"),
1242        **dict.fromkeys(
1243            (
1244                "SESSION",
1245                "GLOBAL",
1246                "KEEP",
1247                "NOKEEP",
1248                "ORDER",
1249                "NOORDER",
1250                "NOCACHE",
1251                "CYCLE",
1252                "NOCYCLE",
1253                "NOMINVALUE",
1254                "NOMAXVALUE",
1255                "NOSCALE",
1256                "NOSHARD",
1257            ),
1258            tuple(),
1259        ),
1260    }
1261
1262    ISOLATED_LOADING_OPTIONS: OPTIONS_TYPE = {"FOR": ("ALL", "INSERT", "NONE")}
1263
1264    USABLES: OPTIONS_TYPE = dict.fromkeys(
1265        ("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA", "CATALOG"), tuple()
1266    )
1267
1268    CAST_ACTIONS: OPTIONS_TYPE = dict.fromkeys(("RENAME", "ADD"), ("FIELDS",))
1269
1270    SCHEMA_BINDING_OPTIONS: OPTIONS_TYPE = {
1271        "TYPE": ("EVOLUTION",),
1272        **dict.fromkeys(("BINDING", "COMPENSATION", "EVOLUTION"), tuple()),
1273    }
1274
1275    PROCEDURE_OPTIONS: OPTIONS_TYPE = {}
1276
1277    EXECUTE_AS_OPTIONS: OPTIONS_TYPE = dict.fromkeys(("CALLER", "SELF", "OWNER"), tuple())
1278
1279    KEY_CONSTRAINT_OPTIONS: OPTIONS_TYPE = {
1280        "NOT": ("ENFORCED",),
1281        "MATCH": (
1282            "FULL",
1283            "PARTIAL",
1284            "SIMPLE",
1285        ),
1286        "INITIALLY": ("DEFERRED", "IMMEDIATE"),
1287        **dict.fromkeys(("DEFERRABLE", "NORELY"), tuple()),
1288    }
1289
1290    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
1291
1292    CLONE_KEYWORDS = {"CLONE", "COPY"}
1293    HISTORICAL_DATA_PREFIX = {"AT", "BEFORE", "END"}
1294    HISTORICAL_DATA_KIND = {"TIMESTAMP", "OFFSET", "STATEMENT", "STREAM"}
1295
1296    OPCLASS_FOLLOW_KEYWORDS = {"ASC", "DESC", "NULLS", "WITH"}
1297
1298    OPTYPE_FOLLOW_TOKENS = {TokenType.COMMA, TokenType.R_PAREN}
1299
1300    TABLE_INDEX_HINT_TOKENS = {TokenType.FORCE, TokenType.IGNORE, TokenType.USE}
1301
1302    VIEW_ATTRIBUTES = {"ENCRYPTION", "SCHEMABINDING", "VIEW_METADATA"}
1303
1304    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
1305    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
1306    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
1307
1308    JSON_KEY_VALUE_SEPARATOR_TOKENS = {TokenType.COLON, TokenType.COMMA, TokenType.IS}
1309
1310    FETCH_TOKENS = ID_VAR_TOKENS - {TokenType.ROW, TokenType.ROWS, TokenType.PERCENT}
1311
1312    ADD_CONSTRAINT_TOKENS = {
1313        TokenType.CONSTRAINT,
1314        TokenType.FOREIGN_KEY,
1315        TokenType.INDEX,
1316        TokenType.KEY,
1317        TokenType.PRIMARY_KEY,
1318        TokenType.UNIQUE,
1319    }
1320
1321    DISTINCT_TOKENS = {TokenType.DISTINCT}
1322
1323    NULL_TOKENS = {TokenType.NULL}
1324
1325    UNNEST_OFFSET_ALIAS_TOKENS = ID_VAR_TOKENS - SET_OPERATIONS
1326
1327    SELECT_START_TOKENS = {TokenType.L_PAREN, TokenType.WITH, TokenType.SELECT}
1328
1329    COPY_INTO_VARLEN_OPTIONS = {"FILE_FORMAT", "COPY_OPTIONS", "FORMAT_OPTIONS", "CREDENTIAL"}
1330
1331    IS_JSON_PREDICATE_KIND = {"VALUE", "SCALAR", "ARRAY", "OBJECT"}
1332
1333    ODBC_DATETIME_LITERALS = {
1334        "d": exp.Date,
1335        "t": exp.Time,
1336        "ts": exp.Timestamp,
1337    }
1338
1339    ON_CONDITION_TOKENS = {"ERROR", "NULL", "TRUE", "FALSE", "EMPTY"}
1340
1341    PRIVILEGE_FOLLOW_TOKENS = {TokenType.ON, TokenType.COMMA, TokenType.L_PAREN}
1342
1343    # The style options for the DESCRIBE statement
1344    DESCRIBE_STYLES = {"ANALYZE", "EXTENDED", "FORMATTED", "HISTORY"}
1345
1346    # The style options for the ANALYZE statement
1347    ANALYZE_STYLES = {
1348        "BUFFER_USAGE_LIMIT",
1349        "FULL",
1350        "LOCAL",
1351        "NO_WRITE_TO_BINLOG",
1352        "SAMPLE",
1353        "SKIP_LOCKED",
1354        "VERBOSE",
1355    }
1356
1357    ANALYZE_EXPRESSION_PARSERS = {
1358        "ALL": lambda self: self._parse_analyze_columns(),
1359        "COMPUTE": lambda self: self._parse_analyze_statistics(),
1360        "DELETE": lambda self: self._parse_analyze_delete(),
1361        "DROP": lambda self: self._parse_analyze_histogram(),
1362        "ESTIMATE": lambda self: self._parse_analyze_statistics(),
1363        "LIST": lambda self: self._parse_analyze_list(),
1364        "PREDICATE": lambda self: self._parse_analyze_columns(),
1365        "UPDATE": lambda self: self._parse_analyze_histogram(),
1366        "VALIDATE": lambda self: self._parse_analyze_validate(),
1367    }
1368
1369    PARTITION_KEYWORDS = {"PARTITION", "SUBPARTITION"}
1370
1371    AMBIGUOUS_ALIAS_TOKENS = (TokenType.LIMIT, TokenType.OFFSET)
1372
1373    OPERATION_MODIFIERS: t.Set[str] = set()
1374
1375    STRICT_CAST = True
1376
1377    PREFIXED_PIVOT_COLUMNS = False
1378    IDENTIFY_PIVOT_STRINGS = False
1379
1380    LOG_DEFAULTS_TO_LN = False
1381
1382    # Whether ADD is present for each column added by ALTER TABLE
1383    ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
1384
1385    # Whether the table sample clause expects CSV syntax
1386    TABLESAMPLE_CSV = False
1387
1388    # The default method used for table sampling
1389    DEFAULT_SAMPLING_METHOD: t.Optional[str] = None
1390
1391    # Whether the SET command needs a delimiter (e.g. "=") for assignments
1392    SET_REQUIRES_ASSIGNMENT_DELIMITER = True
1393
1394    # Whether the TRIM function expects the characters to trim as its first argument
1395    TRIM_PATTERN_FIRST = False
1396
1397    # Whether string aliases are supported `SELECT COUNT(*) 'count'`
1398    STRING_ALIASES = False
1399
1400    # Whether query modifiers such as LIMIT are attached to the UNION node (vs its right operand)
1401    MODIFIERS_ATTACHED_TO_SET_OP = True
1402    SET_OP_MODIFIERS = {"order", "limit", "offset"}
1403
1404    # Whether to parse IF statements that aren't followed by a left parenthesis as commands
1405    NO_PAREN_IF_COMMANDS = True
1406
1407    # Whether the -> and ->> operators expect documents of type JSON (e.g. Postgres)
1408    JSON_ARROWS_REQUIRE_JSON_TYPE = False
1409
1410    # Whether the `:` operator is used to extract a value from a VARIANT column
1411    COLON_IS_VARIANT_EXTRACT = False
1412
1413    # Whether or not a VALUES keyword needs to be followed by '(' to form a VALUES clause.
1414    # If this is True and '(' is not found, the keyword will be treated as an identifier
1415    VALUES_FOLLOWED_BY_PAREN = True
1416
1417    # Whether implicit unnesting is supported, e.g. SELECT 1 FROM y.z AS z, z.a (Redshift)
1418    SUPPORTS_IMPLICIT_UNNEST = False
1419
1420    # Whether or not interval spans are supported, INTERVAL 1 YEAR TO MONTHS
1421    INTERVAL_SPANS = True
1422
1423    # Whether a PARTITION clause can follow a table reference
1424    SUPPORTS_PARTITION_SELECTION = False
1425
1426    # Whether the `name AS expr` schema/column constraint requires parentheses around `expr`
1427    WRAPPED_TRANSFORM_COLUMN_CONSTRAINT = True
1428
1429    # Whether the 'AS' keyword is optional in the CTE definition syntax
1430    OPTIONAL_ALIAS_TOKEN_CTE = True
1431
1432    __slots__ = (
1433        "error_level",
1434        "error_message_context",
1435        "max_errors",
1436        "dialect",
1437        "sql",
1438        "errors",
1439        "_tokens",
1440        "_index",
1441        "_curr",
1442        "_next",
1443        "_prev",
1444        "_prev_comments",
1445    )
1446
1447    # Autofilled
1448    SHOW_TRIE: t.Dict = {}
1449    SET_TRIE: t.Dict = {}
1450
1451    def __init__(
1452        self,
1453        error_level: t.Optional[ErrorLevel] = None,
1454        error_message_context: int = 100,
1455        max_errors: int = 3,
1456        dialect: DialectType = None,
1457    ):
1458        from sqlglot.dialects import Dialect
1459
1460        self.error_level = error_level or ErrorLevel.IMMEDIATE
1461        self.error_message_context = error_message_context
1462        self.max_errors = max_errors
1463        self.dialect = Dialect.get_or_raise(dialect)
1464        self.reset()
1465
1466    def reset(self):
1467        self.sql = ""
1468        self.errors = []
1469        self._tokens = []
1470        self._index = 0
1471        self._curr = None
1472        self._next = None
1473        self._prev = None
1474        self._prev_comments = None
1475
1476    def parse(
1477        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1478    ) -> t.List[t.Optional[exp.Expression]]:
1479        """
1480        Parses a list of tokens and returns a list of syntax trees, one tree
1481        per parsed SQL statement.
1482
1483        Args:
1484            raw_tokens: The list of tokens.
1485            sql: The original SQL string, used to produce helpful debug messages.
1486
1487        Returns:
1488            The list of the produced syntax trees.
1489        """
1490        return self._parse(
1491            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1492        )
1493
1494    def parse_into(
1495        self,
1496        expression_types: exp.IntoType,
1497        raw_tokens: t.List[Token],
1498        sql: t.Optional[str] = None,
1499    ) -> t.List[t.Optional[exp.Expression]]:
1500        """
1501        Parses a list of tokens into a given Expression type. If a collection of Expression
1502        types is given instead, this method will try to parse the token list into each one
1503        of them, stopping at the first for which the parsing succeeds.
1504
1505        Args:
1506            expression_types: The expression type(s) to try and parse the token list into.
1507            raw_tokens: The list of tokens.
1508            sql: The original SQL string, used to produce helpful debug messages.
1509
1510        Returns:
1511            The target Expression.
1512        """
1513        errors = []
1514        for expression_type in ensure_list(expression_types):
1515            parser = self.EXPRESSION_PARSERS.get(expression_type)
1516            if not parser:
1517                raise TypeError(f"No parser registered for {expression_type}")
1518
1519            try:
1520                return self._parse(parser, raw_tokens, sql)
1521            except ParseError as e:
1522                e.errors[0]["into_expression"] = expression_type
1523                errors.append(e)
1524
1525        raise ParseError(
1526            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1527            errors=merge_errors(errors),
1528        ) from errors[-1]
1529
1530    def _parse(
1531        self,
1532        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
1533        raw_tokens: t.List[Token],
1534        sql: t.Optional[str] = None,
1535    ) -> t.List[t.Optional[exp.Expression]]:
1536        self.reset()
1537        self.sql = sql or ""
1538
1539        total = len(raw_tokens)
1540        chunks: t.List[t.List[Token]] = [[]]
1541
1542        for i, token in enumerate(raw_tokens):
1543            if token.token_type == TokenType.SEMICOLON:
1544                if token.comments:
1545                    chunks.append([token])
1546
1547                if i < total - 1:
1548                    chunks.append([])
1549            else:
1550                chunks[-1].append(token)
1551
1552        expressions = []
1553
1554        for tokens in chunks:
1555            self._index = -1
1556            self._tokens = tokens
1557            self._advance()
1558
1559            expressions.append(parse_method(self))
1560
1561            if self._index < len(self._tokens):
1562                self.raise_error("Invalid expression / Unexpected token")
1563
1564            self.check_errors()
1565
1566        return expressions
1567
1568    def check_errors(self) -> None:
1569        """Logs or raises any found errors, depending on the chosen error level setting."""
1570        if self.error_level == ErrorLevel.WARN:
1571            for error in self.errors:
1572                logger.error(str(error))
1573        elif self.error_level == ErrorLevel.RAISE and self.errors:
1574            raise ParseError(
1575                concat_messages(self.errors, self.max_errors),
1576                errors=merge_errors(self.errors),
1577            )
1578
1579    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1580        """
1581        Appends an error in the list of recorded errors or raises it, depending on the chosen
1582        error level setting.
1583        """
1584        token = token or self._curr or self._prev or Token.string("")
1585        start = token.start
1586        end = token.end + 1
1587        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1588        highlight = self.sql[start:end]
1589        end_context = self.sql[end : end + self.error_message_context]
1590
1591        error = ParseError.new(
1592            f"{message}. Line {token.line}, Col: {token.col}.\n"
1593            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1594            description=message,
1595            line=token.line,
1596            col=token.col,
1597            start_context=start_context,
1598            highlight=highlight,
1599            end_context=end_context,
1600        )
1601
1602        if self.error_level == ErrorLevel.IMMEDIATE:
1603            raise error
1604
1605        self.errors.append(error)
1606
1607    def expression(
1608        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1609    ) -> E:
1610        """
1611        Creates a new, validated Expression.
1612
1613        Args:
1614            exp_class: The expression class to instantiate.
1615            comments: An optional list of comments to attach to the expression.
1616            kwargs: The arguments to set for the expression along with their respective values.
1617
1618        Returns:
1619            The target expression.
1620        """
1621        instance = exp_class(**kwargs)
1622        instance.add_comments(comments) if comments else self._add_comments(instance)
1623        return self.validate_expression(instance)
1624
1625    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
1626        if expression and self._prev_comments:
1627            expression.add_comments(self._prev_comments)
1628            self._prev_comments = None
1629
1630    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1631        """
1632        Validates an Expression, making sure that all its mandatory arguments are set.
1633
1634        Args:
1635            expression: The expression to validate.
1636            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1637
1638        Returns:
1639            The validated expression.
1640        """
1641        if self.error_level != ErrorLevel.IGNORE:
1642            for error_message in expression.error_messages(args):
1643                self.raise_error(error_message)
1644
1645        return expression
1646
1647    def _find_sql(self, start: Token, end: Token) -> str:
1648        return self.sql[start.start : end.end + 1]
1649
1650    def _is_connected(self) -> bool:
1651        return self._prev and self._curr and self._prev.end + 1 == self._curr.start
1652
1653    def _advance(self, times: int = 1) -> None:
1654        self._index += times
1655        self._curr = seq_get(self._tokens, self._index)
1656        self._next = seq_get(self._tokens, self._index + 1)
1657
1658        if self._index > 0:
1659            self._prev = self._tokens[self._index - 1]
1660            self._prev_comments = self._prev.comments
1661        else:
1662            self._prev = None
1663            self._prev_comments = None
1664
1665    def _retreat(self, index: int) -> None:
1666        if index != self._index:
1667            self._advance(index - self._index)
1668
1669    def _warn_unsupported(self) -> None:
1670        if len(self._tokens) <= 1:
1671            return
1672
1673        # We use _find_sql because self.sql may comprise multiple chunks, and we're only
1674        # interested in emitting a warning for the one being currently processed.
1675        sql = self._find_sql(self._tokens[0], self._tokens[-1])[: self.error_message_context]
1676
1677        logger.warning(
1678            f"'{sql}' contains unsupported syntax. Falling back to parsing as a 'Command'."
1679        )
1680
1681    def _parse_command(self) -> exp.Command:
1682        self._warn_unsupported()
1683        return self.expression(
1684            exp.Command,
1685            comments=self._prev_comments,
1686            this=self._prev.text.upper(),
1687            expression=self._parse_string(),
1688        )
1689
1690    def _try_parse(self, parse_method: t.Callable[[], T], retreat: bool = False) -> t.Optional[T]:
1691        """
1692        Attemps to backtrack if a parse function that contains a try/catch internally raises an error.
1693        This behavior can be different depending on the uset-set ErrorLevel, so _try_parse aims to
1694        solve this by setting & resetting the parser state accordingly
1695        """
1696        index = self._index
1697        error_level = self.error_level
1698
1699        self.error_level = ErrorLevel.IMMEDIATE
1700        try:
1701            this = parse_method()
1702        except ParseError:
1703            this = None
1704        finally:
1705            if not this or retreat:
1706                self._retreat(index)
1707            self.error_level = error_level
1708
1709        return this
1710
1711    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
1712        start = self._prev
1713        exists = self._parse_exists() if allow_exists else None
1714
1715        self._match(TokenType.ON)
1716
1717        materialized = self._match_text_seq("MATERIALIZED")
1718        kind = self._match_set(self.CREATABLES) and self._prev
1719        if not kind:
1720            return self._parse_as_command(start)
1721
1722        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1723            this = self._parse_user_defined_function(kind=kind.token_type)
1724        elif kind.token_type == TokenType.TABLE:
1725            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
1726        elif kind.token_type == TokenType.COLUMN:
1727            this = self._parse_column()
1728        else:
1729            this = self._parse_id_var()
1730
1731        self._match(TokenType.IS)
1732
1733        return self.expression(
1734            exp.Comment,
1735            this=this,
1736            kind=kind.text,
1737            expression=self._parse_string(),
1738            exists=exists,
1739            materialized=materialized,
1740        )
1741
1742    def _parse_to_table(
1743        self,
1744    ) -> exp.ToTableProperty:
1745        table = self._parse_table_parts(schema=True)
1746        return self.expression(exp.ToTableProperty, this=table)
1747
1748    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
1749    def _parse_ttl(self) -> exp.Expression:
1750        def _parse_ttl_action() -> t.Optional[exp.Expression]:
1751            this = self._parse_bitwise()
1752
1753            if self._match_text_seq("DELETE"):
1754                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
1755            if self._match_text_seq("RECOMPRESS"):
1756                return self.expression(
1757                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
1758                )
1759            if self._match_text_seq("TO", "DISK"):
1760                return self.expression(
1761                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
1762                )
1763            if self._match_text_seq("TO", "VOLUME"):
1764                return self.expression(
1765                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
1766                )
1767
1768            return this
1769
1770        expressions = self._parse_csv(_parse_ttl_action)
1771        where = self._parse_where()
1772        group = self._parse_group()
1773
1774        aggregates = None
1775        if group and self._match(TokenType.SET):
1776            aggregates = self._parse_csv(self._parse_set_item)
1777
1778        return self.expression(
1779            exp.MergeTreeTTL,
1780            expressions=expressions,
1781            where=where,
1782            group=group,
1783            aggregates=aggregates,
1784        )
1785
1786    def _parse_statement(self) -> t.Optional[exp.Expression]:
1787        if self._curr is None:
1788            return None
1789
1790        if self._match_set(self.STATEMENT_PARSERS):
1791            comments = self._prev_comments
1792            stmt = self.STATEMENT_PARSERS[self._prev.token_type](self)
1793            stmt.add_comments(comments, prepend=True)
1794            return stmt
1795
1796        if self._match_set(self.dialect.tokenizer.COMMANDS):
1797            return self._parse_command()
1798
1799        expression = self._parse_expression()
1800        expression = self._parse_set_operations(expression) if expression else self._parse_select()
1801        return self._parse_query_modifiers(expression)
1802
1803    def _parse_drop(self, exists: bool = False) -> exp.Drop | exp.Command:
1804        start = self._prev
1805        temporary = self._match(TokenType.TEMPORARY)
1806        materialized = self._match_text_seq("MATERIALIZED")
1807
1808        kind = self._match_set(self.CREATABLES) and self._prev.text.upper()
1809        if not kind:
1810            return self._parse_as_command(start)
1811
1812        concurrently = self._match_text_seq("CONCURRENTLY")
1813        if_exists = exists or self._parse_exists()
1814
1815        if kind == "COLUMN":
1816            this = self._parse_column()
1817        else:
1818            this = self._parse_table_parts(
1819                schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
1820            )
1821
1822        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
1823
1824        if self._match(TokenType.L_PAREN, advance=False):
1825            expressions = self._parse_wrapped_csv(self._parse_types)
1826        else:
1827            expressions = None
1828
1829        return self.expression(
1830            exp.Drop,
1831            exists=if_exists,
1832            this=this,
1833            expressions=expressions,
1834            kind=self.dialect.CREATABLE_KIND_MAPPING.get(kind) or kind,
1835            temporary=temporary,
1836            materialized=materialized,
1837            cascade=self._match_text_seq("CASCADE"),
1838            constraints=self._match_text_seq("CONSTRAINTS"),
1839            purge=self._match_text_seq("PURGE"),
1840            cluster=cluster,
1841            concurrently=concurrently,
1842        )
1843
1844    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
1845        return (
1846            self._match_text_seq("IF")
1847            and (not not_ or self._match(TokenType.NOT))
1848            and self._match(TokenType.EXISTS)
1849        )
1850
1851    def _parse_create(self) -> exp.Create | exp.Command:
1852        # Note: this can't be None because we've matched a statement parser
1853        start = self._prev
1854
1855        replace = (
1856            start.token_type == TokenType.REPLACE
1857            or self._match_pair(TokenType.OR, TokenType.REPLACE)
1858            or self._match_pair(TokenType.OR, TokenType.ALTER)
1859        )
1860        refresh = self._match_pair(TokenType.OR, TokenType.REFRESH)
1861
1862        unique = self._match(TokenType.UNIQUE)
1863
1864        if self._match_text_seq("CLUSTERED", "COLUMNSTORE"):
1865            clustered = True
1866        elif self._match_text_seq("NONCLUSTERED", "COLUMNSTORE") or self._match_text_seq(
1867            "COLUMNSTORE"
1868        ):
1869            clustered = False
1870        else:
1871            clustered = None
1872
1873        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
1874            self._advance()
1875
1876        properties = None
1877        create_token = self._match_set(self.CREATABLES) and self._prev
1878
1879        if not create_token:
1880            # exp.Properties.Location.POST_CREATE
1881            properties = self._parse_properties()
1882            create_token = self._match_set(self.CREATABLES) and self._prev
1883
1884            if not properties or not create_token:
1885                return self._parse_as_command(start)
1886
1887        concurrently = self._match_text_seq("CONCURRENTLY")
1888        exists = self._parse_exists(not_=True)
1889        this = None
1890        expression: t.Optional[exp.Expression] = None
1891        indexes = None
1892        no_schema_binding = None
1893        begin = None
1894        end = None
1895        clone = None
1896
1897        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
1898            nonlocal properties
1899            if properties and temp_props:
1900                properties.expressions.extend(temp_props.expressions)
1901            elif temp_props:
1902                properties = temp_props
1903
1904        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1905            this = self._parse_user_defined_function(kind=create_token.token_type)
1906
1907            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
1908            extend_props(self._parse_properties())
1909
1910            expression = self._match(TokenType.ALIAS) and self._parse_heredoc()
1911            extend_props(self._parse_properties())
1912
1913            if not expression:
1914                if self._match(TokenType.COMMAND):
1915                    expression = self._parse_as_command(self._prev)
1916                else:
1917                    begin = self._match(TokenType.BEGIN)
1918                    return_ = self._match_text_seq("RETURN")
1919
1920                    if self._match(TokenType.STRING, advance=False):
1921                        # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
1922                        # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
1923                        expression = self._parse_string()
1924                        extend_props(self._parse_properties())
1925                    else:
1926                        expression = self._parse_user_defined_function_expression()
1927
1928                    end = self._match_text_seq("END")
1929
1930                    if return_:
1931                        expression = self.expression(exp.Return, this=expression)
1932        elif create_token.token_type == TokenType.INDEX:
1933            # Postgres allows anonymous indexes, eg. CREATE INDEX IF NOT EXISTS ON t(c)
1934            if not self._match(TokenType.ON):
1935                index = self._parse_id_var()
1936                anonymous = False
1937            else:
1938                index = None
1939                anonymous = True
1940
1941            this = self._parse_index(index=index, anonymous=anonymous)
1942        elif create_token.token_type in self.DB_CREATABLES:
1943            table_parts = self._parse_table_parts(
1944                schema=True, is_db_reference=create_token.token_type == TokenType.SCHEMA
1945            )
1946
1947            # exp.Properties.Location.POST_NAME
1948            self._match(TokenType.COMMA)
1949            extend_props(self._parse_properties(before=True))
1950
1951            this = self._parse_schema(this=table_parts)
1952
1953            # exp.Properties.Location.POST_SCHEMA and POST_WITH
1954            extend_props(self._parse_properties())
1955
1956            self._match(TokenType.ALIAS)
1957            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
1958                # exp.Properties.Location.POST_ALIAS
1959                extend_props(self._parse_properties())
1960
1961            if create_token.token_type == TokenType.SEQUENCE:
1962                expression = self._parse_types()
1963                extend_props(self._parse_properties())
1964            else:
1965                expression = self._parse_ddl_select()
1966
1967            if create_token.token_type == TokenType.TABLE:
1968                # exp.Properties.Location.POST_EXPRESSION
1969                extend_props(self._parse_properties())
1970
1971                indexes = []
1972                while True:
1973                    index = self._parse_index()
1974
1975                    # exp.Properties.Location.POST_INDEX
1976                    extend_props(self._parse_properties())
1977                    if not index:
1978                        break
1979                    else:
1980                        self._match(TokenType.COMMA)
1981                        indexes.append(index)
1982            elif create_token.token_type == TokenType.VIEW:
1983                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
1984                    no_schema_binding = True
1985            elif create_token.token_type in (TokenType.SINK, TokenType.SOURCE):
1986                extend_props(self._parse_properties())
1987
1988            shallow = self._match_text_seq("SHALLOW")
1989
1990            if self._match_texts(self.CLONE_KEYWORDS):
1991                copy = self._prev.text.lower() == "copy"
1992                clone = self.expression(
1993                    exp.Clone, this=self._parse_table(schema=True), shallow=shallow, copy=copy
1994                )
1995
1996        if self._curr and not self._match_set((TokenType.R_PAREN, TokenType.COMMA), advance=False):
1997            return self._parse_as_command(start)
1998
1999        create_kind_text = create_token.text.upper()
2000        return self.expression(
2001            exp.Create,
2002            this=this,
2003            kind=self.dialect.CREATABLE_KIND_MAPPING.get(create_kind_text) or create_kind_text,
2004            replace=replace,
2005            refresh=refresh,
2006            unique=unique,
2007            expression=expression,
2008            exists=exists,
2009            properties=properties,
2010            indexes=indexes,
2011            no_schema_binding=no_schema_binding,
2012            begin=begin,
2013            end=end,
2014            clone=clone,
2015            concurrently=concurrently,
2016            clustered=clustered,
2017        )
2018
2019    def _parse_sequence_properties(self) -> t.Optional[exp.SequenceProperties]:
2020        seq = exp.SequenceProperties()
2021
2022        options = []
2023        index = self._index
2024
2025        while self._curr:
2026            self._match(TokenType.COMMA)
2027            if self._match_text_seq("INCREMENT"):
2028                self._match_text_seq("BY")
2029                self._match_text_seq("=")
2030                seq.set("increment", self._parse_term())
2031            elif self._match_text_seq("MINVALUE"):
2032                seq.set("minvalue", self._parse_term())
2033            elif self._match_text_seq("MAXVALUE"):
2034                seq.set("maxvalue", self._parse_term())
2035            elif self._match(TokenType.START_WITH) or self._match_text_seq("START"):
2036                self._match_text_seq("=")
2037                seq.set("start", self._parse_term())
2038            elif self._match_text_seq("CACHE"):
2039                # T-SQL allows empty CACHE which is initialized dynamically
2040                seq.set("cache", self._parse_number() or True)
2041            elif self._match_text_seq("OWNED", "BY"):
2042                # "OWNED BY NONE" is the default
2043                seq.set("owned", None if self._match_text_seq("NONE") else self._parse_column())
2044            else:
2045                opt = self._parse_var_from_options(self.CREATE_SEQUENCE, raise_unmatched=False)
2046                if opt:
2047                    options.append(opt)
2048                else:
2049                    break
2050
2051        seq.set("options", options if options else None)
2052        return None if self._index == index else seq
2053
2054    def _parse_property_before(self) -> t.Optional[exp.Expression]:
2055        # only used for teradata currently
2056        self._match(TokenType.COMMA)
2057
2058        kwargs = {
2059            "no": self._match_text_seq("NO"),
2060            "dual": self._match_text_seq("DUAL"),
2061            "before": self._match_text_seq("BEFORE"),
2062            "default": self._match_text_seq("DEFAULT"),
2063            "local": (self._match_text_seq("LOCAL") and "LOCAL")
2064            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
2065            "after": self._match_text_seq("AFTER"),
2066            "minimum": self._match_texts(("MIN", "MINIMUM")),
2067            "maximum": self._match_texts(("MAX", "MAXIMUM")),
2068        }
2069
2070        if self._match_texts(self.PROPERTY_PARSERS):
2071            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
2072            try:
2073                return parser(self, **{k: v for k, v in kwargs.items() if v})
2074            except TypeError:
2075                self.raise_error(f"Cannot parse property '{self._prev.text}'")
2076
2077        return None
2078
2079    def _parse_wrapped_properties(self) -> t.List[exp.Expression]:
2080        return self._parse_wrapped_csv(self._parse_property)
2081
2082    def _parse_property(self) -> t.Optional[exp.Expression]:
2083        if self._match_texts(self.PROPERTY_PARSERS):
2084            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
2085
2086        if self._match(TokenType.DEFAULT) and self._match_texts(self.PROPERTY_PARSERS):
2087            return self.PROPERTY_PARSERS[self._prev.text.upper()](self, default=True)
2088
2089        if self._match_text_seq("COMPOUND", "SORTKEY"):
2090            return self._parse_sortkey(compound=True)
2091
2092        if self._match_text_seq("SQL", "SECURITY"):
2093            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
2094
2095        index = self._index
2096        key = self._parse_column()
2097
2098        if not self._match(TokenType.EQ):
2099            self._retreat(index)
2100            return self._parse_sequence_properties()
2101
2102        # Transform the key to exp.Dot if it's dotted identifiers wrapped in exp.Column or to exp.Var otherwise
2103        if isinstance(key, exp.Column):
2104            key = key.to_dot() if len(key.parts) > 1 else exp.var(key.name)
2105
2106        value = self._parse_bitwise() or self._parse_var(any_token=True)
2107
2108        # Transform the value to exp.Var if it was parsed as exp.Column(exp.Identifier())
2109        if isinstance(value, exp.Column):
2110            value = exp.var(value.name)
2111
2112        return self.expression(exp.Property, this=key, value=value)
2113
2114    def _parse_stored(self) -> exp.FileFormatProperty:
2115        self._match(TokenType.ALIAS)
2116
2117        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
2118        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
2119
2120        return self.expression(
2121            exp.FileFormatProperty,
2122            this=(
2123                self.expression(
2124                    exp.InputOutputFormat, input_format=input_format, output_format=output_format
2125                )
2126                if input_format or output_format
2127                else self._parse_var_or_string() or self._parse_number() or self._parse_id_var()
2128            ),
2129        )
2130
2131    def _parse_unquoted_field(self) -> t.Optional[exp.Expression]:
2132        field = self._parse_field()
2133        if isinstance(field, exp.Identifier) and not field.quoted:
2134            field = exp.var(field)
2135
2136        return field
2137
2138    def _parse_property_assignment(self, exp_class: t.Type[E], **kwargs: t.Any) -> E:
2139        self._match(TokenType.EQ)
2140        self._match(TokenType.ALIAS)
2141
2142        return self.expression(exp_class, this=self._parse_unquoted_field(), **kwargs)
2143
2144    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
2145        properties = []
2146        while True:
2147            if before:
2148                prop = self._parse_property_before()
2149            else:
2150                prop = self._parse_property()
2151            if not prop:
2152                break
2153            for p in ensure_list(prop):
2154                properties.append(p)
2155
2156        if properties:
2157            return self.expression(exp.Properties, expressions=properties)
2158
2159        return None
2160
2161    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
2162        return self.expression(
2163            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
2164        )
2165
2166    def _parse_security(self) -> t.Optional[exp.SecurityProperty]:
2167        if self._match_texts(("DEFINER", "INVOKER")):
2168            security_specifier = self._prev.text.upper()
2169            return self.expression(exp.SecurityProperty, this=security_specifier)
2170        return None
2171
2172    def _parse_settings_property(self) -> exp.SettingsProperty:
2173        return self.expression(
2174            exp.SettingsProperty, expressions=self._parse_csv(self._parse_assignment)
2175        )
2176
2177    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
2178        if self._index >= 2:
2179            pre_volatile_token = self._tokens[self._index - 2]
2180        else:
2181            pre_volatile_token = None
2182
2183        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
2184            return exp.VolatileProperty()
2185
2186        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
2187
2188    def _parse_retention_period(self) -> exp.Var:
2189        # Parse TSQL's HISTORY_RETENTION_PERIOD: {INFINITE | <number> DAY | DAYS | MONTH ...}
2190        number = self._parse_number()
2191        number_str = f"{number} " if number else ""
2192        unit = self._parse_var(any_token=True)
2193        return exp.var(f"{number_str}{unit}")
2194
2195    def _parse_system_versioning_property(
2196        self, with_: bool = False
2197    ) -> exp.WithSystemVersioningProperty:
2198        self._match(TokenType.EQ)
2199        prop = self.expression(
2200            exp.WithSystemVersioningProperty,
2201            **{  # type: ignore
2202                "on": True,
2203                "with": with_,
2204            },
2205        )
2206
2207        if self._match_text_seq("OFF"):
2208            prop.set("on", False)
2209            return prop
2210
2211        self._match(TokenType.ON)
2212        if self._match(TokenType.L_PAREN):
2213            while self._curr and not self._match(TokenType.R_PAREN):
2214                if self._match_text_seq("HISTORY_TABLE", "="):
2215                    prop.set("this", self._parse_table_parts())
2216                elif self._match_text_seq("DATA_CONSISTENCY_CHECK", "="):
2217                    prop.set("data_consistency", self._advance_any() and self._prev.text.upper())
2218                elif self._match_text_seq("HISTORY_RETENTION_PERIOD", "="):
2219                    prop.set("retention_period", self._parse_retention_period())
2220
2221                self._match(TokenType.COMMA)
2222
2223        return prop
2224
2225    def _parse_data_deletion_property(self) -> exp.DataDeletionProperty:
2226        self._match(TokenType.EQ)
2227        on = self._match_text_seq("ON") or not self._match_text_seq("OFF")
2228        prop = self.expression(exp.DataDeletionProperty, on=on)
2229
2230        if self._match(TokenType.L_PAREN):
2231            while self._curr and not self._match(TokenType.R_PAREN):
2232                if self._match_text_seq("FILTER_COLUMN", "="):
2233                    prop.set("filter_column", self._parse_column())
2234                elif self._match_text_seq("RETENTION_PERIOD", "="):
2235                    prop.set("retention_period", self._parse_retention_period())
2236
2237                self._match(TokenType.COMMA)
2238
2239        return prop
2240
2241    def _parse_distributed_property(self) -> exp.DistributedByProperty:
2242        kind = "HASH"
2243        expressions: t.Optional[t.List[exp.Expression]] = None
2244        if self._match_text_seq("BY", "HASH"):
2245            expressions = self._parse_wrapped_csv(self._parse_id_var)
2246        elif self._match_text_seq("BY", "RANDOM"):
2247            kind = "RANDOM"
2248
2249        # If the BUCKETS keyword is not present, the number of buckets is AUTO
2250        buckets: t.Optional[exp.Expression] = None
2251        if self._match_text_seq("BUCKETS") and not self._match_text_seq("AUTO"):
2252            buckets = self._parse_number()
2253
2254        return self.expression(
2255            exp.DistributedByProperty,
2256            expressions=expressions,
2257            kind=kind,
2258            buckets=buckets,
2259            order=self._parse_order(),
2260        )
2261
2262    def _parse_composite_key_property(self, expr_type: t.Type[E]) -> E:
2263        self._match_text_seq("KEY")
2264        expressions = self._parse_wrapped_id_vars()
2265        return self.expression(expr_type, expressions=expressions)
2266
2267    def _parse_with_property(self) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
2268        if self._match_text_seq("(", "SYSTEM_VERSIONING"):
2269            prop = self._parse_system_versioning_property(with_=True)
2270            self._match_r_paren()
2271            return prop
2272
2273        if self._match(TokenType.L_PAREN, advance=False):
2274            return self._parse_wrapped_properties()
2275
2276        if self._match_text_seq("JOURNAL"):
2277            return self._parse_withjournaltable()
2278
2279        if self._match_texts(self.VIEW_ATTRIBUTES):
2280            return self.expression(exp.ViewAttributeProperty, this=self._prev.text.upper())
2281
2282        if self._match_text_seq("DATA"):
2283            return self._parse_withdata(no=False)
2284        elif self._match_text_seq("NO", "DATA"):
2285            return self._parse_withdata(no=True)
2286
2287        if self._match(TokenType.SERDE_PROPERTIES, advance=False):
2288            return self._parse_serde_properties(with_=True)
2289
2290        if self._match(TokenType.SCHEMA):
2291            return self.expression(
2292                exp.WithSchemaBindingProperty,
2293                this=self._parse_var_from_options(self.SCHEMA_BINDING_OPTIONS),
2294            )
2295
2296        if self._match_texts(self.PROCEDURE_OPTIONS, advance=False):
2297            return self.expression(
2298                exp.WithProcedureOptions, expressions=self._parse_csv(self._parse_procedure_option)
2299            )
2300
2301        if not self._next:
2302            return None
2303
2304        return self._parse_withisolatedloading()
2305
2306    def _parse_procedure_option(self) -> exp.Expression | None:
2307        if self._match_text_seq("EXECUTE", "AS"):
2308            return self.expression(
2309                exp.ExecuteAsProperty,
2310                this=self._parse_var_from_options(self.EXECUTE_AS_OPTIONS, raise_unmatched=False)
2311                or self._parse_string(),
2312            )
2313
2314        return self._parse_var_from_options(self.PROCEDURE_OPTIONS)
2315
2316    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
2317    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
2318        self._match(TokenType.EQ)
2319
2320        user = self._parse_id_var()
2321        self._match(TokenType.PARAMETER)
2322        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
2323
2324        if not user or not host:
2325            return None
2326
2327        return exp.DefinerProperty(this=f"{user}@{host}")
2328
2329    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
2330        self._match(TokenType.TABLE)
2331        self._match(TokenType.EQ)
2332        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
2333
2334    def _parse_log(self, no: bool = False) -> exp.LogProperty:
2335        return self.expression(exp.LogProperty, no=no)
2336
2337    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
2338        return self.expression(exp.JournalProperty, **kwargs)
2339
2340    def _parse_checksum(self) -> exp.ChecksumProperty:
2341        self._match(TokenType.EQ)
2342
2343        on = None
2344        if self._match(TokenType.ON):
2345            on = True
2346        elif self._match_text_seq("OFF"):
2347            on = False
2348
2349        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
2350
2351    def _parse_cluster(self, wrapped: bool = False) -> exp.Cluster:
2352        return self.expression(
2353            exp.Cluster,
2354            expressions=(
2355                self._parse_wrapped_csv(self._parse_ordered)
2356                if wrapped
2357                else self._parse_csv(self._parse_ordered)
2358            ),
2359        )
2360
2361    def _parse_clustered_by(self) -> exp.ClusteredByProperty:
2362        self._match_text_seq("BY")
2363
2364        self._match_l_paren()
2365        expressions = self._parse_csv(self._parse_column)
2366        self._match_r_paren()
2367
2368        if self._match_text_seq("SORTED", "BY"):
2369            self._match_l_paren()
2370            sorted_by = self._parse_csv(self._parse_ordered)
2371            self._match_r_paren()
2372        else:
2373            sorted_by = None
2374
2375        self._match(TokenType.INTO)
2376        buckets = self._parse_number()
2377        self._match_text_seq("BUCKETS")
2378
2379        return self.expression(
2380            exp.ClusteredByProperty,
2381            expressions=expressions,
2382            sorted_by=sorted_by,
2383            buckets=buckets,
2384        )
2385
2386    def _parse_copy_property(self) -> t.Optional[exp.CopyGrantsProperty]:
2387        if not self._match_text_seq("GRANTS"):
2388            self._retreat(self._index - 1)
2389            return None
2390
2391        return self.expression(exp.CopyGrantsProperty)
2392
2393    def _parse_freespace(self) -> exp.FreespaceProperty:
2394        self._match(TokenType.EQ)
2395        return self.expression(
2396            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
2397        )
2398
2399    def _parse_mergeblockratio(
2400        self, no: bool = False, default: bool = False
2401    ) -> exp.MergeBlockRatioProperty:
2402        if self._match(TokenType.EQ):
2403            return self.expression(
2404                exp.MergeBlockRatioProperty,
2405                this=self._parse_number(),
2406                percent=self._match(TokenType.PERCENT),
2407            )
2408
2409        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
2410
2411    def _parse_datablocksize(
2412        self,
2413        default: t.Optional[bool] = None,
2414        minimum: t.Optional[bool] = None,
2415        maximum: t.Optional[bool] = None,
2416    ) -> exp.DataBlocksizeProperty:
2417        self._match(TokenType.EQ)
2418        size = self._parse_number()
2419
2420        units = None
2421        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
2422            units = self._prev.text
2423
2424        return self.expression(
2425            exp.DataBlocksizeProperty,
2426            size=size,
2427            units=units,
2428            default=default,
2429            minimum=minimum,
2430            maximum=maximum,
2431        )
2432
2433    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
2434        self._match(TokenType.EQ)
2435        always = self._match_text_seq("ALWAYS")
2436        manual = self._match_text_seq("MANUAL")
2437        never = self._match_text_seq("NEVER")
2438        default = self._match_text_seq("DEFAULT")
2439
2440        autotemp = None
2441        if self._match_text_seq("AUTOTEMP"):
2442            autotemp = self._parse_schema()
2443
2444        return self.expression(
2445            exp.BlockCompressionProperty,
2446            always=always,
2447            manual=manual,
2448            never=never,
2449            default=default,
2450            autotemp=autotemp,
2451        )
2452
2453    def _parse_withisolatedloading(self) -> t.Optional[exp.IsolatedLoadingProperty]:
2454        index = self._index
2455        no = self._match_text_seq("NO")
2456        concurrent = self._match_text_seq("CONCURRENT")
2457
2458        if not self._match_text_seq("ISOLATED", "LOADING"):
2459            self._retreat(index)
2460            return None
2461
2462        target = self._parse_var_from_options(self.ISOLATED_LOADING_OPTIONS, raise_unmatched=False)
2463        return self.expression(
2464            exp.IsolatedLoadingProperty, no=no, concurrent=concurrent, target=target
2465        )
2466
2467    def _parse_locking(self) -> exp.LockingProperty:
2468        if self._match(TokenType.TABLE):
2469            kind = "TABLE"
2470        elif self._match(TokenType.VIEW):
2471            kind = "VIEW"
2472        elif self._match(TokenType.ROW):
2473            kind = "ROW"
2474        elif self._match_text_seq("DATABASE"):
2475            kind = "DATABASE"
2476        else:
2477            kind = None
2478
2479        if kind in ("DATABASE", "TABLE", "VIEW"):
2480            this = self._parse_table_parts()
2481        else:
2482            this = None
2483
2484        if self._match(TokenType.FOR):
2485            for_or_in = "FOR"
2486        elif self._match(TokenType.IN):
2487            for_or_in = "IN"
2488        else:
2489            for_or_in = None
2490
2491        if self._match_text_seq("ACCESS"):
2492            lock_type = "ACCESS"
2493        elif self._match_texts(("EXCL", "EXCLUSIVE")):
2494            lock_type = "EXCLUSIVE"
2495        elif self._match_text_seq("SHARE"):
2496            lock_type = "SHARE"
2497        elif self._match_text_seq("READ"):
2498            lock_type = "READ"
2499        elif self._match_text_seq("WRITE"):
2500            lock_type = "WRITE"
2501        elif self._match_text_seq("CHECKSUM"):
2502            lock_type = "CHECKSUM"
2503        else:
2504            lock_type = None
2505
2506        override = self._match_text_seq("OVERRIDE")
2507
2508        return self.expression(
2509            exp.LockingProperty,
2510            this=this,
2511            kind=kind,
2512            for_or_in=for_or_in,
2513            lock_type=lock_type,
2514            override=override,
2515        )
2516
2517    def _parse_partition_by(self) -> t.List[exp.Expression]:
2518        if self._match(TokenType.PARTITION_BY):
2519            return self._parse_csv(self._parse_assignment)
2520        return []
2521
2522    def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
2523        def _parse_partition_bound_expr() -> t.Optional[exp.Expression]:
2524            if self._match_text_seq("MINVALUE"):
2525                return exp.var("MINVALUE")
2526            if self._match_text_seq("MAXVALUE"):
2527                return exp.var("MAXVALUE")
2528            return self._parse_bitwise()
2529
2530        this: t.Optional[exp.Expression | t.List[exp.Expression]] = None
2531        expression = None
2532        from_expressions = None
2533        to_expressions = None
2534
2535        if self._match(TokenType.IN):
2536            this = self._parse_wrapped_csv(self._parse_bitwise)
2537        elif self._match(TokenType.FROM):
2538            from_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
2539            self._match_text_seq("TO")
2540            to_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
2541        elif self._match_text_seq("WITH", "(", "MODULUS"):
2542            this = self._parse_number()
2543            self._match_text_seq(",", "REMAINDER")
2544            expression = self._parse_number()
2545            self._match_r_paren()
2546        else:
2547            self.raise_error("Failed to parse partition bound spec.")
2548
2549        return self.expression(
2550            exp.PartitionBoundSpec,
2551            this=this,
2552            expression=expression,
2553            from_expressions=from_expressions,
2554            to_expressions=to_expressions,
2555        )
2556
2557    # https://www.postgresql.org/docs/current/sql-createtable.html
2558    def _parse_partitioned_of(self) -> t.Optional[exp.PartitionedOfProperty]:
2559        if not self._match_text_seq("OF"):
2560            self._retreat(self._index - 1)
2561            return None
2562
2563        this = self._parse_table(schema=True)
2564
2565        if self._match(TokenType.DEFAULT):
2566            expression: exp.Var | exp.PartitionBoundSpec = exp.var("DEFAULT")
2567        elif self._match_text_seq("FOR", "VALUES"):
2568            expression = self._parse_partition_bound_spec()
2569        else:
2570            self.raise_error("Expecting either DEFAULT or FOR VALUES clause.")
2571
2572        return self.expression(exp.PartitionedOfProperty, this=this, expression=expression)
2573
2574    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
2575        self._match(TokenType.EQ)
2576        return self.expression(
2577            exp.PartitionedByProperty,
2578            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
2579        )
2580
2581    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
2582        if self._match_text_seq("AND", "STATISTICS"):
2583            statistics = True
2584        elif self._match_text_seq("AND", "NO", "STATISTICS"):
2585            statistics = False
2586        else:
2587            statistics = None
2588
2589        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
2590
2591    def _parse_contains_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2592        if self._match_text_seq("SQL"):
2593            return self.expression(exp.SqlReadWriteProperty, this="CONTAINS SQL")
2594        return None
2595
2596    def _parse_modifies_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2597        if self._match_text_seq("SQL", "DATA"):
2598            return self.expression(exp.SqlReadWriteProperty, this="MODIFIES SQL DATA")
2599        return None
2600
2601    def _parse_no_property(self) -> t.Optional[exp.Expression]:
2602        if self._match_text_seq("PRIMARY", "INDEX"):
2603            return exp.NoPrimaryIndexProperty()
2604        if self._match_text_seq("SQL"):
2605            return self.expression(exp.SqlReadWriteProperty, this="NO SQL")
2606        return None
2607
2608    def _parse_on_property(self) -> t.Optional[exp.Expression]:
2609        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
2610            return exp.OnCommitProperty()
2611        if self._match_text_seq("COMMIT", "DELETE", "ROWS"):
2612            return exp.OnCommitProperty(delete=True)
2613        return self.expression(exp.OnProperty, this=self._parse_schema(self._parse_id_var()))
2614
2615    def _parse_reads_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2616        if self._match_text_seq("SQL", "DATA"):
2617            return self.expression(exp.SqlReadWriteProperty, this="READS SQL DATA")
2618        return None
2619
2620    def _parse_distkey(self) -> exp.DistKeyProperty:
2621        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
2622
2623    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
2624        table = self._parse_table(schema=True)
2625
2626        options = []
2627        while self._match_texts(("INCLUDING", "EXCLUDING")):
2628            this = self._prev.text.upper()
2629
2630            id_var = self._parse_id_var()
2631            if not id_var:
2632                return None
2633
2634            options.append(
2635                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
2636            )
2637
2638        return self.expression(exp.LikeProperty, this=table, expressions=options)
2639
2640    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
2641        return self.expression(
2642            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
2643        )
2644
2645    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
2646        self._match(TokenType.EQ)
2647        return self.expression(
2648            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
2649        )
2650
2651    def _parse_remote_with_connection(self) -> exp.RemoteWithConnectionModelProperty:
2652        self._match_text_seq("WITH", "CONNECTION")
2653        return self.expression(
2654            exp.RemoteWithConnectionModelProperty, this=self._parse_table_parts()
2655        )
2656
2657    def _parse_returns(self) -> exp.ReturnsProperty:
2658        value: t.Optional[exp.Expression]
2659        null = None
2660        is_table = self._match(TokenType.TABLE)
2661
2662        if is_table:
2663            if self._match(TokenType.LT):
2664                value = self.expression(
2665                    exp.Schema,
2666                    this="TABLE",
2667                    expressions=self._parse_csv(self._parse_struct_types),
2668                )
2669                if not self._match(TokenType.GT):
2670                    self.raise_error("Expecting >")
2671            else:
2672                value = self._parse_schema(exp.var("TABLE"))
2673        elif self._match_text_seq("NULL", "ON", "NULL", "INPUT"):
2674            null = True
2675            value = None
2676        else:
2677            value = self._parse_types()
2678
2679        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table, null=null)
2680
2681    def _parse_describe(self) -> exp.Describe:
2682        kind = self._match_set(self.CREATABLES) and self._prev.text
2683        style = self._match_texts(self.DESCRIBE_STYLES) and self._prev.text.upper()
2684        if self._match(TokenType.DOT):
2685            style = None
2686            self._retreat(self._index - 2)
2687
2688        format = self._parse_property() if self._match(TokenType.FORMAT, advance=False) else None
2689
2690        if self._match_set(self.STATEMENT_PARSERS, advance=False):
2691            this = self._parse_statement()
2692        else:
2693            this = self._parse_table(schema=True)
2694
2695        properties = self._parse_properties()
2696        expressions = properties.expressions if properties else None
2697        partition = self._parse_partition()
2698        return self.expression(
2699            exp.Describe,
2700            this=this,
2701            style=style,
2702            kind=kind,
2703            expressions=expressions,
2704            partition=partition,
2705            format=format,
2706        )
2707
2708    def _parse_multitable_inserts(self, comments: t.Optional[t.List[str]]) -> exp.MultitableInserts:
2709        kind = self._prev.text.upper()
2710        expressions = []
2711
2712        def parse_conditional_insert() -> t.Optional[exp.ConditionalInsert]:
2713            if self._match(TokenType.WHEN):
2714                expression = self._parse_disjunction()
2715                self._match(TokenType.THEN)
2716            else:
2717                expression = None
2718
2719            else_ = self._match(TokenType.ELSE)
2720
2721            if not self._match(TokenType.INTO):
2722                return None
2723
2724            return self.expression(
2725                exp.ConditionalInsert,
2726                this=self.expression(
2727                    exp.Insert,
2728                    this=self._parse_table(schema=True),
2729                    expression=self._parse_derived_table_values(),
2730                ),
2731                expression=expression,
2732                else_=else_,
2733            )
2734
2735        expression = parse_conditional_insert()
2736        while expression is not None:
2737            expressions.append(expression)
2738            expression = parse_conditional_insert()
2739
2740        return self.expression(
2741            exp.MultitableInserts,
2742            kind=kind,
2743            comments=comments,
2744            expressions=expressions,
2745            source=self._parse_table(),
2746        )
2747
2748    def _parse_insert(self) -> t.Union[exp.Insert, exp.MultitableInserts]:
2749        comments = []
2750        hint = self._parse_hint()
2751        overwrite = self._match(TokenType.OVERWRITE)
2752        ignore = self._match(TokenType.IGNORE)
2753        local = self._match_text_seq("LOCAL")
2754        alternative = None
2755        is_function = None
2756
2757        if self._match_text_seq("DIRECTORY"):
2758            this: t.Optional[exp.Expression] = self.expression(
2759                exp.Directory,
2760                this=self._parse_var_or_string(),
2761                local=local,
2762                row_format=self._parse_row_format(match_row=True),
2763            )
2764        else:
2765            if self._match_set((TokenType.FIRST, TokenType.ALL)):
2766                comments += ensure_list(self._prev_comments)
2767                return self._parse_multitable_inserts(comments)
2768
2769            if self._match(TokenType.OR):
2770                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
2771
2772            self._match(TokenType.INTO)
2773            comments += ensure_list(self._prev_comments)
2774            self._match(TokenType.TABLE)
2775            is_function = self._match(TokenType.FUNCTION)
2776
2777            this = (
2778                self._parse_table(schema=True, parse_partition=True)
2779                if not is_function
2780                else self._parse_function()
2781            )
2782            if isinstance(this, exp.Table) and self._match(TokenType.ALIAS, advance=False):
2783                this.set("alias", self._parse_table_alias())
2784
2785        returning = self._parse_returning()
2786
2787        return self.expression(
2788            exp.Insert,
2789            comments=comments,
2790            hint=hint,
2791            is_function=is_function,
2792            this=this,
2793            stored=self._match_text_seq("STORED") and self._parse_stored(),
2794            by_name=self._match_text_seq("BY", "NAME"),
2795            exists=self._parse_exists(),
2796            where=self._match_pair(TokenType.REPLACE, TokenType.WHERE) and self._parse_assignment(),
2797            partition=self._match(TokenType.PARTITION_BY) and self._parse_partitioned_by(),
2798            settings=self._match_text_seq("SETTINGS") and self._parse_settings_property(),
2799            expression=self._parse_derived_table_values() or self._parse_ddl_select(),
2800            conflict=self._parse_on_conflict(),
2801            returning=returning or self._parse_returning(),
2802            overwrite=overwrite,
2803            alternative=alternative,
2804            ignore=ignore,
2805            source=self._match(TokenType.TABLE) and self._parse_table(),
2806        )
2807
2808    def _parse_kill(self) -> exp.Kill:
2809        kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
2810
2811        return self.expression(
2812            exp.Kill,
2813            this=self._parse_primary(),
2814            kind=kind,
2815        )
2816
2817    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
2818        conflict = self._match_text_seq("ON", "CONFLICT")
2819        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
2820
2821        if not conflict and not duplicate:
2822            return None
2823
2824        conflict_keys = None
2825        constraint = None
2826
2827        if conflict:
2828            if self._match_text_seq("ON", "CONSTRAINT"):
2829                constraint = self._parse_id_var()
2830            elif self._match(TokenType.L_PAREN):
2831                conflict_keys = self._parse_csv(self._parse_id_var)
2832                self._match_r_paren()
2833
2834        action = self._parse_var_from_options(self.CONFLICT_ACTIONS)
2835        if self._prev.token_type == TokenType.UPDATE:
2836            self._match(TokenType.SET)
2837            expressions = self._parse_csv(self._parse_equality)
2838        else:
2839            expressions = None
2840
2841        return self.expression(
2842            exp.OnConflict,
2843            duplicate=duplicate,
2844            expressions=expressions,
2845            action=action,
2846            conflict_keys=conflict_keys,
2847            constraint=constraint,
2848            where=self._parse_where(),
2849        )
2850
2851    def _parse_returning(self) -> t.Optional[exp.Returning]:
2852        if not self._match(TokenType.RETURNING):
2853            return None
2854        return self.expression(
2855            exp.Returning,
2856            expressions=self._parse_csv(self._parse_expression),
2857            into=self._match(TokenType.INTO) and self._parse_table_part(),
2858        )
2859
2860    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2861        if not self._match(TokenType.FORMAT):
2862            return None
2863        return self._parse_row_format()
2864
2865    def _parse_serde_properties(self, with_: bool = False) -> t.Optional[exp.SerdeProperties]:
2866        index = self._index
2867        with_ = with_ or self._match_text_seq("WITH")
2868
2869        if not self._match(TokenType.SERDE_PROPERTIES):
2870            self._retreat(index)
2871            return None
2872        return self.expression(
2873            exp.SerdeProperties,
2874            **{  # type: ignore
2875                "expressions": self._parse_wrapped_properties(),
2876                "with": with_,
2877            },
2878        )
2879
2880    def _parse_row_format(
2881        self, match_row: bool = False
2882    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2883        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
2884            return None
2885
2886        if self._match_text_seq("SERDE"):
2887            this = self._parse_string()
2888
2889            serde_properties = self._parse_serde_properties()
2890
2891            return self.expression(
2892                exp.RowFormatSerdeProperty, this=this, serde_properties=serde_properties
2893            )
2894
2895        self._match_text_seq("DELIMITED")
2896
2897        kwargs = {}
2898
2899        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
2900            kwargs["fields"] = self._parse_string()
2901            if self._match_text_seq("ESCAPED", "BY"):
2902                kwargs["escaped"] = self._parse_string()
2903        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
2904            kwargs["collection_items"] = self._parse_string()
2905        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
2906            kwargs["map_keys"] = self._parse_string()
2907        if self._match_text_seq("LINES", "TERMINATED", "BY"):
2908            kwargs["lines"] = self._parse_string()
2909        if self._match_text_seq("NULL", "DEFINED", "AS"):
2910            kwargs["null"] = self._parse_string()
2911
2912        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
2913
2914    def _parse_load(self) -> exp.LoadData | exp.Command:
2915        if self._match_text_seq("DATA"):
2916            local = self._match_text_seq("LOCAL")
2917            self._match_text_seq("INPATH")
2918            inpath = self._parse_string()
2919            overwrite = self._match(TokenType.OVERWRITE)
2920            self._match_pair(TokenType.INTO, TokenType.TABLE)
2921
2922            return self.expression(
2923                exp.LoadData,
2924                this=self._parse_table(schema=True),
2925                local=local,
2926                overwrite=overwrite,
2927                inpath=inpath,
2928                partition=self._parse_partition(),
2929                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
2930                serde=self._match_text_seq("SERDE") and self._parse_string(),
2931            )
2932        return self._parse_as_command(self._prev)
2933
2934    def _parse_delete(self) -> exp.Delete:
2935        # This handles MySQL's "Multiple-Table Syntax"
2936        # https://dev.mysql.com/doc/refman/8.0/en/delete.html
2937        tables = None
2938        if not self._match(TokenType.FROM, advance=False):
2939            tables = self._parse_csv(self._parse_table) or None
2940
2941        returning = self._parse_returning()
2942
2943        return self.expression(
2944            exp.Delete,
2945            tables=tables,
2946            this=self._match(TokenType.FROM) and self._parse_table(joins=True),
2947            using=self._match(TokenType.USING) and self._parse_table(joins=True),
2948            cluster=self._match(TokenType.ON) and self._parse_on_property(),
2949            where=self._parse_where(),
2950            returning=returning or self._parse_returning(),
2951            limit=self._parse_limit(),
2952        )
2953
2954    def _parse_update(self) -> exp.Update:
2955        this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
2956        expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
2957        returning = self._parse_returning()
2958        return self.expression(
2959            exp.Update,
2960            **{  # type: ignore
2961                "this": this,
2962                "expressions": expressions,
2963                "from": self._parse_from(joins=True),
2964                "where": self._parse_where(),
2965                "returning": returning or self._parse_returning(),
2966                "order": self._parse_order(),
2967                "limit": self._parse_limit(),
2968            },
2969        )
2970
2971    def _parse_uncache(self) -> exp.Uncache:
2972        if not self._match(TokenType.TABLE):
2973            self.raise_error("Expecting TABLE after UNCACHE")
2974
2975        return self.expression(
2976            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
2977        )
2978
2979    def _parse_cache(self) -> exp.Cache:
2980        lazy = self._match_text_seq("LAZY")
2981        self._match(TokenType.TABLE)
2982        table = self._parse_table(schema=True)
2983
2984        options = []
2985        if self._match_text_seq("OPTIONS"):
2986            self._match_l_paren()
2987            k = self._parse_string()
2988            self._match(TokenType.EQ)
2989            v = self._parse_string()
2990            options = [k, v]
2991            self._match_r_paren()
2992
2993        self._match(TokenType.ALIAS)
2994        return self.expression(
2995            exp.Cache,
2996            this=table,
2997            lazy=lazy,
2998            options=options,
2999            expression=self._parse_select(nested=True),
3000        )
3001
3002    def _parse_partition(self) -> t.Optional[exp.Partition]:
3003        if not self._match_texts(self.PARTITION_KEYWORDS):
3004            return None
3005
3006        return self.expression(
3007            exp.Partition,
3008            subpartition=self._prev.text.upper() == "SUBPARTITION",
3009            expressions=self._parse_wrapped_csv(self._parse_assignment),
3010        )
3011
3012    def _parse_value(self) -> t.Optional[exp.Tuple]:
3013        def _parse_value_expression() -> t.Optional[exp.Expression]:
3014            if self.dialect.SUPPORTS_VALUES_DEFAULT and self._match(TokenType.DEFAULT):
3015                return exp.var(self._prev.text.upper())
3016            return self._parse_expression()
3017
3018        if self._match(TokenType.L_PAREN):
3019            expressions = self._parse_csv(_parse_value_expression)
3020            self._match_r_paren()
3021            return self.expression(exp.Tuple, expressions=expressions)
3022
3023        # In some dialects we can have VALUES 1, 2 which results in 1 column & 2 rows.
3024        expression = self._parse_expression()
3025        if expression:
3026            return self.expression(exp.Tuple, expressions=[expression])
3027        return None
3028
3029    def _parse_projections(self) -> t.List[exp.Expression]:
3030        return self._parse_expressions()
3031
3032    def _parse_select(
3033        self,
3034        nested: bool = False,
3035        table: bool = False,
3036        parse_subquery_alias: bool = True,
3037        parse_set_operation: bool = True,
3038    ) -> t.Optional[exp.Expression]:
3039        cte = self._parse_with()
3040
3041        if cte:
3042            this = self._parse_statement()
3043
3044            if not this:
3045                self.raise_error("Failed to parse any statement following CTE")
3046                return cte
3047
3048            if "with" in this.arg_types:
3049                this.set("with", cte)
3050            else:
3051                self.raise_error(f"{this.key} does not support CTE")
3052                this = cte
3053
3054            return this
3055
3056        # duckdb supports leading with FROM x
3057        from_ = self._parse_from() if self._match(TokenType.FROM, advance=False) else None
3058
3059        if self._match(TokenType.SELECT):
3060            comments = self._prev_comments
3061
3062            hint = self._parse_hint()
3063
3064            if self._next and not self._next.token_type == TokenType.DOT:
3065                all_ = self._match(TokenType.ALL)
3066                distinct = self._match_set(self.DISTINCT_TOKENS)
3067            else:
3068                all_, distinct = None, None
3069
3070            kind = (
3071                self._match(TokenType.ALIAS)
3072                and self._match_texts(("STRUCT", "VALUE"))
3073                and self._prev.text.upper()
3074            )
3075
3076            if distinct:
3077                distinct = self.expression(
3078                    exp.Distinct,
3079                    on=self._parse_value() if self._match(TokenType.ON) else None,
3080                )
3081
3082            if all_ and distinct:
3083                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
3084
3085            operation_modifiers = []
3086            while self._curr and self._match_texts(self.OPERATION_MODIFIERS):
3087                operation_modifiers.append(exp.var(self._prev.text.upper()))
3088
3089            limit = self._parse_limit(top=True)
3090            projections = self._parse_projections()
3091
3092            this = self.expression(
3093                exp.Select,
3094                kind=kind,
3095                hint=hint,
3096                distinct=distinct,
3097                expressions=projections,
3098                limit=limit,
3099                operation_modifiers=operation_modifiers or None,
3100            )
3101            this.comments = comments
3102
3103            into = self._parse_into()
3104            if into:
3105                this.set("into", into)
3106
3107            if not from_:
3108                from_ = self._parse_from()
3109
3110            if from_:
3111                this.set("from", from_)
3112
3113            this = self._parse_query_modifiers(this)
3114        elif (table or nested) and self._match(TokenType.L_PAREN):
3115            if self._match_set((TokenType.PIVOT, TokenType.UNPIVOT)):
3116                this = self._parse_simplified_pivot(
3117                    is_unpivot=self._prev.token_type == TokenType.UNPIVOT
3118                )
3119            elif self._match(TokenType.FROM):
3120                from_ = self._parse_from(skip_from_token=True)
3121                # Support parentheses for duckdb FROM-first syntax
3122                select = self._parse_select()
3123                if select:
3124                    select.set("from", from_)
3125                    this = select
3126                else:
3127                    this = exp.select("*").from_(t.cast(exp.From, from_))
3128            else:
3129                this = (
3130                    self._parse_table()
3131                    if table
3132                    else self._parse_select(nested=True, parse_set_operation=False)
3133                )
3134
3135                # Transform exp.Values into a exp.Table to pass through parse_query_modifiers
3136                # in case a modifier (e.g. join) is following
3137                if table and isinstance(this, exp.Values) and this.alias:
3138                    alias = this.args["alias"].pop()
3139                    this = exp.Table(this=this, alias=alias)
3140
3141                this = self._parse_query_modifiers(self._parse_set_operations(this))
3142
3143            self._match_r_paren()
3144
3145            # We return early here so that the UNION isn't attached to the subquery by the
3146            # following call to _parse_set_operations, but instead becomes the parent node
3147            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
3148        elif self._match(TokenType.VALUES, advance=False):
3149            this = self._parse_derived_table_values()
3150        elif from_:
3151            this = exp.select("*").from_(from_.this, copy=False)
3152        elif self._match(TokenType.SUMMARIZE):
3153            table = self._match(TokenType.TABLE)
3154            this = self._parse_select() or self._parse_string() or self._parse_table()
3155            return self.expression(exp.Summarize, this=this, table=table)
3156        elif self._match(TokenType.DESCRIBE):
3157            this = self._parse_describe()
3158        elif self._match_text_seq("STREAM"):
3159            this = self._parse_function()
3160            if this:
3161                this = self.expression(exp.Stream, this=this)
3162            else:
3163                self._retreat(self._index - 1)
3164        else:
3165            this = None
3166
3167        return self._parse_set_operations(this) if parse_set_operation else this
3168
3169    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
3170        if not skip_with_token and not self._match(TokenType.WITH):
3171            return None
3172
3173        comments = self._prev_comments
3174        recursive = self._match(TokenType.RECURSIVE)
3175
3176        last_comments = None
3177        expressions = []
3178        while True:
3179            expressions.append(self._parse_cte())
3180            if last_comments:
3181                expressions[-1].add_comments(last_comments)
3182
3183            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
3184                break
3185            else:
3186                self._match(TokenType.WITH)
3187
3188            last_comments = self._prev_comments
3189
3190        return self.expression(
3191            exp.With, comments=comments, expressions=expressions, recursive=recursive
3192        )
3193
3194    def _parse_cte(self) -> t.Optional[exp.CTE]:
3195        index = self._index
3196
3197        alias = self._parse_table_alias(self.ID_VAR_TOKENS)
3198        if not alias or not alias.this:
3199            self.raise_error("Expected CTE to have alias")
3200
3201        if not self._match(TokenType.ALIAS) and not self.OPTIONAL_ALIAS_TOKEN_CTE:
3202            self._retreat(index)
3203            return None
3204
3205        comments = self._prev_comments
3206
3207        if self._match_text_seq("NOT", "MATERIALIZED"):
3208            materialized = False
3209        elif self._match_text_seq("MATERIALIZED"):
3210            materialized = True
3211        else:
3212            materialized = None
3213
3214        cte = self.expression(
3215            exp.CTE,
3216            this=self._parse_wrapped(self._parse_statement),
3217            alias=alias,
3218            materialized=materialized,
3219            comments=comments,
3220        )
3221
3222        if isinstance(cte.this, exp.Values):
3223            cte.set("this", exp.select("*").from_(exp.alias_(cte.this, "_values", table=True)))
3224
3225        return cte
3226
3227    def _parse_table_alias(
3228        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
3229    ) -> t.Optional[exp.TableAlias]:
3230        # In some dialects, LIMIT and OFFSET can act as both identifiers and keywords (clauses)
3231        # so this section tries to parse the clause version and if it fails, it treats the token
3232        # as an identifier (alias)
3233        if self._can_parse_limit_or_offset():
3234            return None
3235
3236        any_token = self._match(TokenType.ALIAS)
3237        alias = (
3238            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
3239            or self._parse_string_as_identifier()
3240        )
3241
3242        index = self._index
3243        if self._match(TokenType.L_PAREN):
3244            columns = self._parse_csv(self._parse_function_parameter)
3245            self._match_r_paren() if columns else self._retreat(index)
3246        else:
3247            columns = None
3248
3249        if not alias and not columns:
3250            return None
3251
3252        table_alias = self.expression(exp.TableAlias, this=alias, columns=columns)
3253
3254        # We bubble up comments from the Identifier to the TableAlias
3255        if isinstance(alias, exp.Identifier):
3256            table_alias.add_comments(alias.pop_comments())
3257
3258        return table_alias
3259
3260    def _parse_subquery(
3261        self, this: t.Optional[exp.Expression], parse_alias: bool = True
3262    ) -> t.Optional[exp.Subquery]:
3263        if not this:
3264            return None
3265
3266        return self.expression(
3267            exp.Subquery,
3268            this=this,
3269            pivots=self._parse_pivots(),
3270            alias=self._parse_table_alias() if parse_alias else None,
3271            sample=self._parse_table_sample(),
3272        )
3273
3274    def _implicit_unnests_to_explicit(self, this: E) -> E:
3275        from sqlglot.optimizer.normalize_identifiers import normalize_identifiers as _norm
3276
3277        refs = {_norm(this.args["from"].this.copy(), dialect=self.dialect).alias_or_name}
3278        for i, join in enumerate(this.args.get("joins") or []):
3279            table = join.this
3280            normalized_table = table.copy()
3281            normalized_table.meta["maybe_column"] = True
3282            normalized_table = _norm(normalized_table, dialect=self.dialect)
3283
3284            if isinstance(table, exp.Table) and not join.args.get("on"):
3285                if normalized_table.parts[0].name in refs:
3286                    table_as_column = table.to_column()
3287                    unnest = exp.Unnest(expressions=[table_as_column])
3288
3289                    # Table.to_column creates a parent Alias node that we want to convert to
3290                    # a TableAlias and attach to the Unnest, so it matches the parser's output
3291                    if isinstance(table.args.get("alias"), exp.TableAlias):
3292                        table_as_column.replace(table_as_column.this)
3293                        exp.alias_(unnest, None, table=[table.args["alias"].this], copy=False)
3294
3295                    table.replace(unnest)
3296
3297            refs.add(normalized_table.alias_or_name)
3298
3299        return this
3300
3301    def _parse_query_modifiers(
3302        self, this: t.Optional[exp.Expression]
3303    ) -> t.Optional[exp.Expression]:
3304        if isinstance(this, (exp.Query, exp.Table)):
3305            for join in self._parse_joins():
3306                this.append("joins", join)
3307            for lateral in iter(self._parse_lateral, None):
3308                this.append("laterals", lateral)
3309
3310            while True:
3311                if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
3312                    parser = self.QUERY_MODIFIER_PARSERS[self._curr.token_type]
3313                    key, expression = parser(self)
3314
3315                    if expression:
3316                        this.set(key, expression)
3317                        if key == "limit":
3318                            offset = expression.args.pop("offset", None)
3319
3320                            if offset:
3321                                offset = exp.Offset(expression=offset)
3322                                this.set("offset", offset)
3323
3324                                limit_by_expressions = expression.expressions
3325                                expression.set("expressions", None)
3326                                offset.set("expressions", limit_by_expressions)
3327                        continue
3328                break
3329
3330        if self.SUPPORTS_IMPLICIT_UNNEST and this and this.args.get("from"):
3331            this = self._implicit_unnests_to_explicit(this)
3332
3333        return this
3334
3335    def _parse_hint_fallback_to_string(self) -> t.Optional[exp.Hint]:
3336        start = self._curr
3337        while self._curr:
3338            self._advance()
3339
3340        end = self._tokens[self._index - 1]
3341        return exp.Hint(expressions=[self._find_sql(start, end)])
3342
3343    def _parse_hint_function_call(self) -> t.Optional[exp.Expression]:
3344        return self._parse_function_call()
3345
3346    def _parse_hint_body(self) -> t.Optional[exp.Hint]:
3347        start_index = self._index
3348        should_fallback_to_string = False
3349
3350        hints = []
3351        try:
3352            for hint in iter(
3353                lambda: self._parse_csv(
3354                    lambda: self._parse_hint_function_call() or self._parse_var(upper=True),
3355                ),
3356                [],
3357            ):
3358                hints.extend(hint)
3359        except ParseError:
3360            should_fallback_to_string = True
3361
3362        if should_fallback_to_string or self._curr:
3363            self._retreat(start_index)
3364            return self._parse_hint_fallback_to_string()
3365
3366        return self.expression(exp.Hint, expressions=hints)
3367
3368    def _parse_hint(self) -> t.Optional[exp.Hint]:
3369        if self._match(TokenType.HINT) and self._prev_comments:
3370            return exp.maybe_parse(self._prev_comments[0], into=exp.Hint, dialect=self.dialect)
3371
3372        return None
3373
3374    def _parse_into(self) -> t.Optional[exp.Into]:
3375        if not self._match(TokenType.INTO):
3376            return None
3377
3378        temp = self._match(TokenType.TEMPORARY)
3379        unlogged = self._match_text_seq("UNLOGGED")
3380        self._match(TokenType.TABLE)
3381
3382        return self.expression(
3383            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
3384        )
3385
3386    def _parse_from(
3387        self, joins: bool = False, skip_from_token: bool = False
3388    ) -> t.Optional[exp.From]:
3389        if not skip_from_token and not self._match(TokenType.FROM):
3390            return None
3391
3392        return self.expression(
3393            exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
3394        )
3395
3396    def _parse_match_recognize_measure(self) -> exp.MatchRecognizeMeasure:
3397        return self.expression(
3398            exp.MatchRecognizeMeasure,
3399            window_frame=self._match_texts(("FINAL", "RUNNING")) and self._prev.text.upper(),
3400            this=self._parse_expression(),
3401        )
3402
3403    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
3404        if not self._match(TokenType.MATCH_RECOGNIZE):
3405            return None
3406
3407        self._match_l_paren()
3408
3409        partition = self._parse_partition_by()
3410        order = self._parse_order()
3411
3412        measures = (
3413            self._parse_csv(self._parse_match_recognize_measure)
3414            if self._match_text_seq("MEASURES")
3415            else None
3416        )
3417
3418        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
3419            rows = exp.var("ONE ROW PER MATCH")
3420        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
3421            text = "ALL ROWS PER MATCH"
3422            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
3423                text += " SHOW EMPTY MATCHES"
3424            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
3425                text += " OMIT EMPTY MATCHES"
3426            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
3427                text += " WITH UNMATCHED ROWS"
3428            rows = exp.var(text)
3429        else:
3430            rows = None
3431
3432        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
3433            text = "AFTER MATCH SKIP"
3434            if self._match_text_seq("PAST", "LAST", "ROW"):
3435                text += " PAST LAST ROW"
3436            elif self._match_text_seq("TO", "NEXT", "ROW"):
3437                text += " TO NEXT ROW"
3438            elif self._match_text_seq("TO", "FIRST"):
3439                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
3440            elif self._match_text_seq("TO", "LAST"):
3441                text += f" TO LAST {self._advance_any().text}"  # type: ignore
3442            after = exp.var(text)
3443        else:
3444            after = None
3445
3446        if self._match_text_seq("PATTERN"):
3447            self._match_l_paren()
3448
3449            if not self._curr:
3450                self.raise_error("Expecting )", self._curr)
3451
3452            paren = 1
3453            start = self._curr
3454
3455            while self._curr and paren > 0:
3456                if self._curr.token_type == TokenType.L_PAREN:
3457                    paren += 1
3458                if self._curr.token_type == TokenType.R_PAREN:
3459                    paren -= 1
3460
3461                end = self._prev
3462                self._advance()
3463
3464            if paren > 0:
3465                self.raise_error("Expecting )", self._curr)
3466
3467            pattern = exp.var(self._find_sql(start, end))
3468        else:
3469            pattern = None
3470
3471        define = (
3472            self._parse_csv(self._parse_name_as_expression)
3473            if self._match_text_seq("DEFINE")
3474            else None
3475        )
3476
3477        self._match_r_paren()
3478
3479        return self.expression(
3480            exp.MatchRecognize,
3481            partition_by=partition,
3482            order=order,
3483            measures=measures,
3484            rows=rows,
3485            after=after,
3486            pattern=pattern,
3487            define=define,
3488            alias=self._parse_table_alias(),
3489        )
3490
3491    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
3492        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
3493        if not cross_apply and self._match_pair(TokenType.OUTER, TokenType.APPLY):
3494            cross_apply = False
3495
3496        if cross_apply is not None:
3497            this = self._parse_select(table=True)
3498            view = None
3499            outer = None
3500        elif self._match(TokenType.LATERAL):
3501            this = self._parse_select(table=True)
3502            view = self._match(TokenType.VIEW)
3503            outer = self._match(TokenType.OUTER)
3504        else:
3505            return None
3506
3507        if not this:
3508            this = (
3509                self._parse_unnest()
3510                or self._parse_function()
3511                or self._parse_id_var(any_token=False)
3512            )
3513
3514            while self._match(TokenType.DOT):
3515                this = exp.Dot(
3516                    this=this,
3517                    expression=self._parse_function() or self._parse_id_var(any_token=False),
3518                )
3519
3520        if view:
3521            table = self._parse_id_var(any_token=False)
3522            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
3523            table_alias: t.Optional[exp.TableAlias] = self.expression(
3524                exp.TableAlias, this=table, columns=columns
3525            )
3526        elif isinstance(this, (exp.Subquery, exp.Unnest)) and this.alias:
3527            # We move the alias from the lateral's child node to the lateral itself
3528            table_alias = this.args["alias"].pop()
3529        else:
3530            table_alias = self._parse_table_alias()
3531
3532        return self.expression(
3533            exp.Lateral,
3534            this=this,
3535            view=view,
3536            outer=outer,
3537            alias=table_alias,
3538            cross_apply=cross_apply,
3539        )
3540
3541    def _parse_join_parts(
3542        self,
3543    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
3544        return (
3545            self._match_set(self.JOIN_METHODS) and self._prev,
3546            self._match_set(self.JOIN_SIDES) and self._prev,
3547            self._match_set(self.JOIN_KINDS) and self._prev,
3548        )
3549
3550    def _parse_using_identifiers(self) -> t.List[exp.Expression]:
3551        def _parse_column_as_identifier() -> t.Optional[exp.Expression]:
3552            this = self._parse_column()
3553            if isinstance(this, exp.Column):
3554                return this.this
3555            return this
3556
3557        return self._parse_wrapped_csv(_parse_column_as_identifier, optional=True)
3558
3559    def _parse_join(
3560        self, skip_join_token: bool = False, parse_bracket: bool = False
3561    ) -> t.Optional[exp.Join]:
3562        if self._match(TokenType.COMMA):
3563            return self.expression(exp.Join, this=self._parse_table())
3564
3565        index = self._index
3566        method, side, kind = self._parse_join_parts()
3567        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
3568        join = self._match(TokenType.JOIN) or (kind and kind.token_type == TokenType.STRAIGHT_JOIN)
3569
3570        if not skip_join_token and not join:
3571            self._retreat(index)
3572            kind = None
3573            method = None
3574            side = None
3575
3576        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
3577        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
3578
3579        if not skip_join_token and not join and not outer_apply and not cross_apply:
3580            return None
3581
3582        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table(parse_bracket=parse_bracket)}
3583        if kind and kind.token_type == TokenType.ARRAY and self._match(TokenType.COMMA):
3584            kwargs["expressions"] = self._parse_csv(
3585                lambda: self._parse_table(parse_bracket=parse_bracket)
3586            )
3587
3588        if method:
3589            kwargs["method"] = method.text
3590        if side:
3591            kwargs["side"] = side.text
3592        if kind:
3593            kwargs["kind"] = kind.text
3594        if hint:
3595            kwargs["hint"] = hint
3596
3597        if self._match(TokenType.MATCH_CONDITION):
3598            kwargs["match_condition"] = self._parse_wrapped(self._parse_comparison)
3599
3600        if self._match(TokenType.ON):
3601            kwargs["on"] = self._parse_assignment()
3602        elif self._match(TokenType.USING):
3603            kwargs["using"] = self._parse_using_identifiers()
3604        elif (
3605            not (outer_apply or cross_apply)
3606            and not isinstance(kwargs["this"], exp.Unnest)
3607            and not (kind and kind.token_type in (TokenType.CROSS, TokenType.ARRAY))
3608        ):
3609            index = self._index
3610            joins: t.Optional[list] = list(self._parse_joins())
3611
3612            if joins and self._match(TokenType.ON):
3613                kwargs["on"] = self._parse_assignment()
3614            elif joins and self._match(TokenType.USING):
3615                kwargs["using"] = self._parse_using_identifiers()
3616            else:
3617                joins = None
3618                self._retreat(index)
3619
3620            kwargs["this"].set("joins", joins if joins else None)
3621
3622        comments = [c for token in (method, side, kind) if token for c in token.comments]
3623        return self.expression(exp.Join, comments=comments, **kwargs)
3624
3625    def _parse_opclass(self) -> t.Optional[exp.Expression]:
3626        this = self._parse_assignment()
3627
3628        if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
3629            return this
3630
3631        if not self._match_set(self.OPTYPE_FOLLOW_TOKENS, advance=False):
3632            return self.expression(exp.Opclass, this=this, expression=self._parse_table_parts())
3633
3634        return this
3635
3636    def _parse_index_params(self) -> exp.IndexParameters:
3637        using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
3638
3639        if self._match(TokenType.L_PAREN, advance=False):
3640            columns = self._parse_wrapped_csv(self._parse_with_operator)
3641        else:
3642            columns = None
3643
3644        include = self._parse_wrapped_id_vars() if self._match_text_seq("INCLUDE") else None
3645        partition_by = self._parse_partition_by()
3646        with_storage = self._match(TokenType.WITH) and self._parse_wrapped_properties()
3647        tablespace = (
3648            self._parse_var(any_token=True)
3649            if self._match_text_seq("USING", "INDEX", "TABLESPACE")
3650            else None
3651        )
3652        where = self._parse_where()
3653
3654        on = self._parse_field() if self._match(TokenType.ON) else None
3655
3656        return self.expression(
3657            exp.IndexParameters,
3658            using=using,
3659            columns=columns,
3660            include=include,
3661            partition_by=partition_by,
3662            where=where,
3663            with_storage=with_storage,
3664            tablespace=tablespace,
3665            on=on,
3666        )
3667
3668    def _parse_index(
3669        self, index: t.Optional[exp.Expression] = None, anonymous: bool = False
3670    ) -> t.Optional[exp.Index]:
3671        if index or anonymous:
3672            unique = None
3673            primary = None
3674            amp = None
3675
3676            self._match(TokenType.ON)
3677            self._match(TokenType.TABLE)  # hive
3678            table = self._parse_table_parts(schema=True)
3679        else:
3680            unique = self._match(TokenType.UNIQUE)
3681            primary = self._match_text_seq("PRIMARY")
3682            amp = self._match_text_seq("AMP")
3683
3684            if not self._match(TokenType.INDEX):
3685                return None
3686
3687            index = self._parse_id_var()
3688            table = None
3689
3690        params = self._parse_index_params()
3691
3692        return self.expression(
3693            exp.Index,
3694            this=index,
3695            table=table,
3696            unique=unique,
3697            primary=primary,
3698            amp=amp,
3699            params=params,
3700        )
3701
3702    def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
3703        hints: t.List[exp.Expression] = []
3704        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
3705            # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
3706            hints.append(
3707                self.expression(
3708                    exp.WithTableHint,
3709                    expressions=self._parse_csv(
3710                        lambda: self._parse_function() or self._parse_var(any_token=True)
3711                    ),
3712                )
3713            )
3714            self._match_r_paren()
3715        else:
3716            # https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
3717            while self._match_set(self.TABLE_INDEX_HINT_TOKENS):
3718                hint = exp.IndexTableHint(this=self._prev.text.upper())
3719
3720                self._match_set((TokenType.INDEX, TokenType.KEY))
3721                if self._match(TokenType.FOR):
3722                    hint.set("target", self._advance_any() and self._prev.text.upper())
3723
3724                hint.set("expressions", self._parse_wrapped_id_vars())
3725                hints.append(hint)
3726
3727        return hints or None
3728
3729    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
3730        return (
3731            (not schema and self._parse_function(optional_parens=False))
3732            or self._parse_id_var(any_token=False)
3733            or self._parse_string_as_identifier()
3734            or self._parse_placeholder()
3735        )
3736
3737    def _parse_table_parts(
3738        self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
3739    ) -> exp.Table:
3740        catalog = None
3741        db = None
3742        table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
3743
3744        while self._match(TokenType.DOT):
3745            if catalog:
3746                # This allows nesting the table in arbitrarily many dot expressions if needed
3747                table = self.expression(
3748                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
3749                )
3750            else:
3751                catalog = db
3752                db = table
3753                # "" used for tsql FROM a..b case
3754                table = self._parse_table_part(schema=schema) or ""
3755
3756        if (
3757            wildcard
3758            and self._is_connected()
3759            and (isinstance(table, exp.Identifier) or not table)
3760            and self._match(TokenType.STAR)
3761        ):
3762            if isinstance(table, exp.Identifier):
3763                table.args["this"] += "*"
3764            else:
3765                table = exp.Identifier(this="*")
3766
3767        # We bubble up comments from the Identifier to the Table
3768        comments = table.pop_comments() if isinstance(table, exp.Expression) else None
3769
3770        if is_db_reference:
3771            catalog = db
3772            db = table
3773            table = None
3774
3775        if not table and not is_db_reference:
3776            self.raise_error(f"Expected table name but got {self._curr}")
3777        if not db and is_db_reference:
3778            self.raise_error(f"Expected database name but got {self._curr}")
3779
3780        table = self.expression(
3781            exp.Table,
3782            comments=comments,
3783            this=table,
3784            db=db,
3785            catalog=catalog,
3786        )
3787
3788        changes = self._parse_changes()
3789        if changes:
3790            table.set("changes", changes)
3791
3792        at_before = self._parse_historical_data()
3793        if at_before:
3794            table.set("when", at_before)
3795
3796        pivots = self._parse_pivots()
3797        if pivots:
3798            table.set("pivots", pivots)
3799
3800        return table
3801
3802    def _parse_table(
3803        self,
3804        schema: bool = False,
3805        joins: bool = False,
3806        alias_tokens: t.Optional[t.Collection[TokenType]] = None,
3807        parse_bracket: bool = False,
3808        is_db_reference: bool = False,
3809        parse_partition: bool = False,
3810    ) -> t.Optional[exp.Expression]:
3811        lateral = self._parse_lateral()
3812        if lateral:
3813            return lateral
3814
3815        unnest = self._parse_unnest()
3816        if unnest:
3817            return unnest
3818
3819        values = self._parse_derived_table_values()
3820        if values:
3821            return values
3822
3823        subquery = self._parse_select(table=True)
3824        if subquery:
3825            if not subquery.args.get("pivots"):
3826                subquery.set("pivots", self._parse_pivots())
3827            return subquery
3828
3829        bracket = parse_bracket and self._parse_bracket(None)
3830        bracket = self.expression(exp.Table, this=bracket) if bracket else None
3831
3832        rows_from = self._match_text_seq("ROWS", "FROM") and self._parse_wrapped_csv(
3833            self._parse_table
3834        )
3835        rows_from = self.expression(exp.Table, rows_from=rows_from) if rows_from else None
3836
3837        only = self._match(TokenType.ONLY)
3838
3839        this = t.cast(
3840            exp.Expression,
3841            bracket
3842            or rows_from
3843            or self._parse_bracket(
3844                self._parse_table_parts(schema=schema, is_db_reference=is_db_reference)
3845            ),
3846        )
3847
3848        if only:
3849            this.set("only", only)
3850
3851        # Postgres supports a wildcard (table) suffix operator, which is a no-op in this context
3852        self._match_text_seq("*")
3853
3854        parse_partition = parse_partition or self.SUPPORTS_PARTITION_SELECTION
3855        if parse_partition and self._match(TokenType.PARTITION, advance=False):
3856            this.set("partition", self._parse_partition())
3857
3858        if schema:
3859            return self._parse_schema(this=this)
3860
3861        version = self._parse_version()
3862
3863        if version:
3864            this.set("version", version)
3865
3866        if self.dialect.ALIAS_POST_TABLESAMPLE:
3867            this.set("sample", self._parse_table_sample())
3868
3869        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
3870        if alias:
3871            this.set("alias", alias)
3872
3873        if isinstance(this, exp.Table) and self._match_text_seq("AT"):
3874            return self.expression(
3875                exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
3876            )
3877
3878        this.set("hints", self._parse_table_hints())
3879
3880        if not this.args.get("pivots"):
3881            this.set("pivots", self._parse_pivots())
3882
3883        if not self.dialect.ALIAS_POST_TABLESAMPLE:
3884            this.set("sample", self._parse_table_sample())
3885
3886        if joins:
3887            for join in self._parse_joins():
3888                this.append("joins", join)
3889
3890        if self._match_pair(TokenType.WITH, TokenType.ORDINALITY):
3891            this.set("ordinality", True)
3892            this.set("alias", self._parse_table_alias())
3893
3894        return this
3895
3896    def _parse_version(self) -> t.Optional[exp.Version]:
3897        if self._match(TokenType.TIMESTAMP_SNAPSHOT):
3898            this = "TIMESTAMP"
3899        elif self._match(TokenType.VERSION_SNAPSHOT):
3900            this = "VERSION"
3901        else:
3902            return None
3903
3904        if self._match_set((TokenType.FROM, TokenType.BETWEEN)):
3905            kind = self._prev.text.upper()
3906            start = self._parse_bitwise()
3907            self._match_texts(("TO", "AND"))
3908            end = self._parse_bitwise()
3909            expression: t.Optional[exp.Expression] = self.expression(
3910                exp.Tuple, expressions=[start, end]
3911            )
3912        elif self._match_text_seq("CONTAINED", "IN"):
3913            kind = "CONTAINED IN"
3914            expression = self.expression(
3915                exp.Tuple, expressions=self._parse_wrapped_csv(self._parse_bitwise)
3916            )
3917        elif self._match(TokenType.ALL):
3918            kind = "ALL"
3919            expression = None
3920        else:
3921            self._match_text_seq("AS", "OF")
3922            kind = "AS OF"
3923            expression = self._parse_type()
3924
3925        return self.expression(exp.Version, this=this, expression=expression, kind=kind)
3926
3927    def _parse_historical_data(self) -> t.Optional[exp.HistoricalData]:
3928        # https://docs.snowflake.com/en/sql-reference/constructs/at-before
3929        index = self._index
3930        historical_data = None
3931        if self._match_texts(self.HISTORICAL_DATA_PREFIX):
3932            this = self._prev.text.upper()
3933            kind = (
3934                self._match(TokenType.L_PAREN)
3935                and self._match_texts(self.HISTORICAL_DATA_KIND)
3936                and self._prev.text.upper()
3937            )
3938            expression = self._match(TokenType.FARROW) and self._parse_bitwise()
3939
3940            if expression:
3941                self._match_r_paren()
3942                historical_data = self.expression(
3943                    exp.HistoricalData, this=this, kind=kind, expression=expression
3944                )
3945            else:
3946                self._retreat(index)
3947
3948        return historical_data
3949
3950    def _parse_changes(self) -> t.Optional[exp.Changes]:
3951        if not self._match_text_seq("CHANGES", "(", "INFORMATION", "=>"):
3952            return None
3953
3954        information = self._parse_var(any_token=True)
3955        self._match_r_paren()
3956
3957        return self.expression(
3958            exp.Changes,
3959            information=information,
3960            at_before=self._parse_historical_data(),
3961            end=self._parse_historical_data(),
3962        )
3963
3964    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
3965        if not self._match(TokenType.UNNEST):
3966            return None
3967
3968        expressions = self._parse_wrapped_csv(self._parse_equality)
3969        offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
3970
3971        alias = self._parse_table_alias() if with_alias else None
3972
3973        if alias:
3974            if self.dialect.UNNEST_COLUMN_ONLY:
3975                if alias.args.get("columns"):
3976                    self.raise_error("Unexpected extra column alias in unnest.")
3977
3978                alias.set("columns", [alias.this])
3979                alias.set("this", None)
3980
3981            columns = alias.args.get("columns") or []
3982            if offset and len(expressions) < len(columns):
3983                offset = columns.pop()
3984
3985        if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
3986            self._match(TokenType.ALIAS)
3987            offset = self._parse_id_var(
3988                any_token=False, tokens=self.UNNEST_OFFSET_ALIAS_TOKENS
3989            ) or exp.to_identifier("offset")
3990
3991        return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
3992
3993    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
3994        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
3995        if not is_derived and not (
3996            # ClickHouse's `FORMAT Values` is equivalent to `VALUES`
3997            self._match_text_seq("VALUES") or self._match_text_seq("FORMAT", "VALUES")
3998        ):
3999            return None
4000
4001        expressions = self._parse_csv(self._parse_value)
4002        alias = self._parse_table_alias()
4003
4004        if is_derived:
4005            self._match_r_paren()
4006
4007        return self.expression(
4008            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
4009        )
4010
4011    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
4012        if not self._match(TokenType.TABLE_SAMPLE) and not (
4013            as_modifier and self._match_text_seq("USING", "SAMPLE")
4014        ):
4015            return None
4016
4017        bucket_numerator = None
4018        bucket_denominator = None
4019        bucket_field = None
4020        percent = None
4021        size = None
4022        seed = None
4023
4024        method = self._parse_var(tokens=(TokenType.ROW,), upper=True)
4025        matched_l_paren = self._match(TokenType.L_PAREN)
4026
4027        if self.TABLESAMPLE_CSV:
4028            num = None
4029            expressions = self._parse_csv(self._parse_primary)
4030        else:
4031            expressions = None
4032            num = (
4033                self._parse_factor()
4034                if self._match(TokenType.NUMBER, advance=False)
4035                else self._parse_primary() or self._parse_placeholder()
4036            )
4037
4038        if self._match_text_seq("BUCKET"):
4039            bucket_numerator = self._parse_number()
4040            self._match_text_seq("OUT", "OF")
4041            bucket_denominator = bucket_denominator = self._parse_number()
4042            self._match(TokenType.ON)
4043            bucket_field = self._parse_field()
4044        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
4045            percent = num
4046        elif self._match(TokenType.ROWS) or not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
4047            size = num
4048        else:
4049            percent = num
4050
4051        if matched_l_paren:
4052            self._match_r_paren()
4053
4054        if self._match(TokenType.L_PAREN):
4055            method = self._parse_var(upper=True)
4056            seed = self._match(TokenType.COMMA) and self._parse_number()
4057            self._match_r_paren()
4058        elif self._match_texts(("SEED", "REPEATABLE")):
4059            seed = self._parse_wrapped(self._parse_number)
4060
4061        if not method and self.DEFAULT_SAMPLING_METHOD:
4062            method = exp.var(self.DEFAULT_SAMPLING_METHOD)
4063
4064        return self.expression(
4065            exp.TableSample,
4066            expressions=expressions,
4067            method=method,
4068            bucket_numerator=bucket_numerator,
4069            bucket_denominator=bucket_denominator,
4070            bucket_field=bucket_field,
4071            percent=percent,
4072            size=size,
4073            seed=seed,
4074        )
4075
4076    def _parse_pivots(self) -> t.Optional[t.List[exp.Pivot]]:
4077        return list(iter(self._parse_pivot, None)) or None
4078
4079    def _parse_joins(self) -> t.Iterator[exp.Join]:
4080        return iter(self._parse_join, None)
4081
4082    def _parse_unpivot_columns(self) -> t.Optional[exp.UnpivotColumns]:
4083        if not self._match(TokenType.INTO):
4084            return None
4085
4086        return self.expression(
4087            exp.UnpivotColumns,
4088            this=self._match_text_seq("NAME") and self._parse_column(),
4089            expressions=self._match_text_seq("VALUE") and self._parse_csv(self._parse_column),
4090        )
4091
4092    # https://duckdb.org/docs/sql/statements/pivot
4093    def _parse_simplified_pivot(self, is_unpivot: t.Optional[bool] = None) -> exp.Pivot:
4094        def _parse_on() -> t.Optional[exp.Expression]:
4095            this = self._parse_bitwise()
4096
4097            if self._match(TokenType.IN):
4098                # PIVOT ... ON col IN (row_val1, row_val2)
4099                return self._parse_in(this)
4100            if self._match(TokenType.ALIAS, advance=False):
4101                # UNPIVOT ... ON (col1, col2, col3) AS row_val
4102                return self._parse_alias(this)
4103
4104            return this
4105
4106        this = self._parse_table()
4107        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
4108        into = self._parse_unpivot_columns()
4109        using = self._match(TokenType.USING) and self._parse_csv(
4110            lambda: self._parse_alias(self._parse_function())
4111        )
4112        group = self._parse_group()
4113
4114        return self.expression(
4115            exp.Pivot,
4116            this=this,
4117            expressions=expressions,
4118            using=using,
4119            group=group,
4120            unpivot=is_unpivot,
4121            into=into,
4122        )
4123
4124    def _parse_pivot_in(self) -> exp.In | exp.PivotAny:
4125        def _parse_aliased_expression() -> t.Optional[exp.Expression]:
4126            this = self._parse_select_or_expression()
4127
4128            self._match(TokenType.ALIAS)
4129            alias = self._parse_bitwise()
4130            if alias:
4131                if isinstance(alias, exp.Column) and not alias.db:
4132                    alias = alias.this
4133                return self.expression(exp.PivotAlias, this=this, alias=alias)
4134
4135            return this
4136
4137        value = self._parse_column()
4138
4139        if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
4140            self.raise_error("Expecting IN (")
4141
4142        if self._match(TokenType.ANY):
4143            exprs: t.List[exp.Expression] = ensure_list(exp.PivotAny(this=self._parse_order()))
4144        else:
4145            exprs = self._parse_csv(_parse_aliased_expression)
4146
4147        self._match_r_paren()
4148        return self.expression(exp.In, this=value, expressions=exprs)
4149
4150    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
4151        index = self._index
4152        include_nulls = None
4153
4154        if self._match(TokenType.PIVOT):
4155            unpivot = False
4156        elif self._match(TokenType.UNPIVOT):
4157            unpivot = True
4158
4159            # https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
4160            if self._match_text_seq("INCLUDE", "NULLS"):
4161                include_nulls = True
4162            elif self._match_text_seq("EXCLUDE", "NULLS"):
4163                include_nulls = False
4164        else:
4165            return None
4166
4167        expressions = []
4168
4169        if not self._match(TokenType.L_PAREN):
4170            self._retreat(index)
4171            return None
4172
4173        if unpivot:
4174            expressions = self._parse_csv(self._parse_column)
4175        else:
4176            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
4177
4178        if not expressions:
4179            self.raise_error("Failed to parse PIVOT's aggregation list")
4180
4181        if not self._match(TokenType.FOR):
4182            self.raise_error("Expecting FOR")
4183
4184        field = self._parse_pivot_in()
4185        default_on_null = self._match_text_seq("DEFAULT", "ON", "NULL") and self._parse_wrapped(
4186            self._parse_bitwise
4187        )
4188
4189        self._match_r_paren()
4190
4191        pivot = self.expression(
4192            exp.Pivot,
4193            expressions=expressions,
4194            field=field,
4195            unpivot=unpivot,
4196            include_nulls=include_nulls,
4197            default_on_null=default_on_null,
4198        )
4199
4200        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
4201            pivot.set("alias", self._parse_table_alias())
4202
4203        if not unpivot:
4204            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
4205
4206            columns: t.List[exp.Expression] = []
4207            for fld in pivot.args["field"].expressions:
4208                field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
4209                for name in names:
4210                    if self.PREFIXED_PIVOT_COLUMNS:
4211                        name = f"{name}_{field_name}" if name else field_name
4212                    else:
4213                        name = f"{field_name}_{name}" if name else field_name
4214
4215                    columns.append(exp.to_identifier(name))
4216
4217            pivot.set("columns", columns)
4218
4219        return pivot
4220
4221    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
4222        return [agg.alias for agg in aggregations]
4223
4224    def _parse_prewhere(self, skip_where_token: bool = False) -> t.Optional[exp.PreWhere]:
4225        if not skip_where_token and not self._match(TokenType.PREWHERE):
4226            return None
4227
4228        return self.expression(
4229            exp.PreWhere, comments=self._prev_comments, this=self._parse_assignment()
4230        )
4231
4232    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
4233        if not skip_where_token and not self._match(TokenType.WHERE):
4234            return None
4235
4236        return self.expression(
4237            exp.Where, comments=self._prev_comments, this=self._parse_assignment()
4238        )
4239
4240    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
4241        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
4242            return None
4243
4244        elements: t.Dict[str, t.Any] = defaultdict(list)
4245
4246        if self._match(TokenType.ALL):
4247            elements["all"] = True
4248        elif self._match(TokenType.DISTINCT):
4249            elements["all"] = False
4250
4251        while True:
4252            index = self._index
4253
4254            elements["expressions"].extend(
4255                self._parse_csv(
4256                    lambda: None
4257                    if self._match_set((TokenType.CUBE, TokenType.ROLLUP), advance=False)
4258                    else self._parse_assignment()
4259                )
4260            )
4261
4262            before_with_index = self._index
4263            with_prefix = self._match(TokenType.WITH)
4264
4265            if self._match(TokenType.ROLLUP):
4266                elements["rollup"].append(
4267                    self._parse_cube_or_rollup(exp.Rollup, with_prefix=with_prefix)
4268                )
4269            elif self._match(TokenType.CUBE):
4270                elements["cube"].append(
4271                    self._parse_cube_or_rollup(exp.Cube, with_prefix=with_prefix)
4272                )
4273            elif self._match(TokenType.GROUPING_SETS):
4274                elements["grouping_sets"].append(
4275                    self.expression(
4276                        exp.GroupingSets,
4277                        expressions=self._parse_wrapped_csv(self._parse_grouping_set),
4278                    )
4279                )
4280            elif self._match_text_seq("TOTALS"):
4281                elements["totals"] = True  # type: ignore
4282
4283            if before_with_index <= self._index <= before_with_index + 1:
4284                self._retreat(before_with_index)
4285                break
4286
4287            if index == self._index:
4288                break
4289
4290        return self.expression(exp.Group, **elements)  # type: ignore
4291
4292    def _parse_cube_or_rollup(self, kind: t.Type[E], with_prefix: bool = False) -> E:
4293        return self.expression(
4294            kind, expressions=[] if with_prefix else self._parse_wrapped_csv(self._parse_column)
4295        )
4296
4297    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
4298        if self._match(TokenType.L_PAREN):
4299            grouping_set = self._parse_csv(self._parse_column)
4300            self._match_r_paren()
4301            return self.expression(exp.Tuple, expressions=grouping_set)
4302
4303        return self._parse_column()
4304
4305    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
4306        if not skip_having_token and not self._match(TokenType.HAVING):
4307            return None
4308        return self.expression(exp.Having, this=self._parse_assignment())
4309
4310    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
4311        if not self._match(TokenType.QUALIFY):
4312            return None
4313        return self.expression(exp.Qualify, this=self._parse_assignment())
4314
4315    def _parse_connect(self, skip_start_token: bool = False) -> t.Optional[exp.Connect]:
4316        if skip_start_token:
4317            start = None
4318        elif self._match(TokenType.START_WITH):
4319            start = self._parse_assignment()
4320        else:
4321            return None
4322
4323        self._match(TokenType.CONNECT_BY)
4324        nocycle = self._match_text_seq("NOCYCLE")
4325        self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
4326            exp.Prior, this=self._parse_bitwise()
4327        )
4328        connect = self._parse_assignment()
4329        self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
4330
4331        if not start and self._match(TokenType.START_WITH):
4332            start = self._parse_assignment()
4333
4334        return self.expression(exp.Connect, start=start, connect=connect, nocycle=nocycle)
4335
4336    def _parse_name_as_expression(self) -> t.Optional[exp.Expression]:
4337        this = self._parse_id_var(any_token=True)
4338        if self._match(TokenType.ALIAS):
4339            this = self.expression(exp.Alias, alias=this, this=self._parse_assignment())
4340        return this
4341
4342    def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
4343        if self._match_text_seq("INTERPOLATE"):
4344            return self._parse_wrapped_csv(self._parse_name_as_expression)
4345        return None
4346
4347    def _parse_order(
4348        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
4349    ) -> t.Optional[exp.Expression]:
4350        siblings = None
4351        if not skip_order_token and not self._match(TokenType.ORDER_BY):
4352            if not self._match(TokenType.ORDER_SIBLINGS_BY):
4353                return this
4354
4355            siblings = True
4356
4357        return self.expression(
4358            exp.Order,
4359            this=this,
4360            expressions=self._parse_csv(self._parse_ordered),
4361            siblings=siblings,
4362        )
4363
4364    def _parse_sort(self, exp_class: t.Type[E], token: TokenType) -> t.Optional[E]:
4365        if not self._match(token):
4366            return None
4367        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
4368
4369    def _parse_ordered(
4370        self, parse_method: t.Optional[t.Callable] = None
4371    ) -> t.Optional[exp.Ordered]:
4372        this = parse_method() if parse_method else self._parse_assignment()
4373        if not this:
4374            return None
4375
4376        if this.name.upper() == "ALL" and self.dialect.SUPPORTS_ORDER_BY_ALL:
4377            this = exp.var("ALL")
4378
4379        asc = self._match(TokenType.ASC)
4380        desc = self._match(TokenType.DESC) or (asc and False)
4381
4382        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
4383        is_nulls_last = self._match_text_seq("NULLS", "LAST")
4384
4385        nulls_first = is_nulls_first or False
4386        explicitly_null_ordered = is_nulls_first or is_nulls_last
4387
4388        if (
4389            not explicitly_null_ordered
4390            and (
4391                (not desc and self.dialect.NULL_ORDERING == "nulls_are_small")
4392                or (desc and self.dialect.NULL_ORDERING != "nulls_are_small")
4393            )
4394            and self.dialect.NULL_ORDERING != "nulls_are_last"
4395        ):
4396            nulls_first = True
4397
4398        if self._match_text_seq("WITH", "FILL"):
4399            with_fill = self.expression(
4400                exp.WithFill,
4401                **{  # type: ignore
4402                    "from": self._match(TokenType.FROM) and self._parse_bitwise(),
4403                    "to": self._match_text_seq("TO") and self._parse_bitwise(),
4404                    "step": self._match_text_seq("STEP") and self._parse_bitwise(),
4405                    "interpolate": self._parse_interpolate(),
4406                },
4407            )
4408        else:
4409            with_fill = None
4410
4411        return self.expression(
4412            exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
4413        )
4414
4415    def _parse_limit(
4416        self,
4417        this: t.Optional[exp.Expression] = None,
4418        top: bool = False,
4419        skip_limit_token: bool = False,
4420    ) -> t.Optional[exp.Expression]:
4421        if skip_limit_token or self._match(TokenType.TOP if top else TokenType.LIMIT):
4422            comments = self._prev_comments
4423            if top:
4424                limit_paren = self._match(TokenType.L_PAREN)
4425                expression = self._parse_term() if limit_paren else self._parse_number()
4426
4427                if limit_paren:
4428                    self._match_r_paren()
4429            else:
4430                expression = self._parse_term()
4431
4432            if self._match(TokenType.COMMA):
4433                offset = expression
4434                expression = self._parse_term()
4435            else:
4436                offset = None
4437
4438            limit_exp = self.expression(
4439                exp.Limit,
4440                this=this,
4441                expression=expression,
4442                offset=offset,
4443                comments=comments,
4444                expressions=self._parse_limit_by(),
4445            )
4446
4447            return limit_exp
4448
4449        if self._match(TokenType.FETCH):
4450            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
4451            direction = self._prev.text.upper() if direction else "FIRST"
4452
4453            count = self._parse_field(tokens=self.FETCH_TOKENS)
4454            percent = self._match(TokenType.PERCENT)
4455
4456            self._match_set((TokenType.ROW, TokenType.ROWS))
4457
4458            only = self._match_text_seq("ONLY")
4459            with_ties = self._match_text_seq("WITH", "TIES")
4460
4461            if only and with_ties:
4462                self.raise_error("Cannot specify both ONLY and WITH TIES in FETCH clause")
4463
4464            return self.expression(
4465                exp.Fetch,
4466                direction=direction,
4467                count=count,
4468                percent=percent,
4469                with_ties=with_ties,
4470            )
4471
4472        return this
4473
4474    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4475        if not self._match(TokenType.OFFSET):
4476            return this
4477
4478        count = self._parse_term()
4479        self._match_set((TokenType.ROW, TokenType.ROWS))
4480
4481        return self.expression(
4482            exp.Offset, this=this, expression=count, expressions=self._parse_limit_by()
4483        )
4484
4485    def _can_parse_limit_or_offset(self) -> bool:
4486        if not self._match_set(self.AMBIGUOUS_ALIAS_TOKENS, advance=False):
4487            return False
4488
4489        index = self._index
4490        result = bool(
4491            self._try_parse(self._parse_limit, retreat=True)
4492            or self._try_parse(self._parse_offset, retreat=True)
4493        )
4494        self._retreat(index)
4495        return result
4496
4497    def _parse_limit_by(self) -> t.Optional[t.List[exp.Expression]]:
4498        return self._match_text_seq("BY") and self._parse_csv(self._parse_bitwise)
4499
4500    def _parse_locks(self) -> t.List[exp.Lock]:
4501        locks = []
4502        while True:
4503            if self._match_text_seq("FOR", "UPDATE"):
4504                update = True
4505            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
4506                "LOCK", "IN", "SHARE", "MODE"
4507            ):
4508                update = False
4509            else:
4510                break
4511
4512            expressions = None
4513            if self._match_text_seq("OF"):
4514                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
4515
4516            wait: t.Optional[bool | exp.Expression] = None
4517            if self._match_text_seq("NOWAIT"):
4518                wait = True
4519            elif self._match_text_seq("WAIT"):
4520                wait = self._parse_primary()
4521            elif self._match_text_seq("SKIP", "LOCKED"):
4522                wait = False
4523
4524            locks.append(
4525                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
4526            )
4527
4528        return locks
4529
4530    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4531        while this and self._match_set(self.SET_OPERATIONS):
4532            token_type = self._prev.token_type
4533
4534            if token_type == TokenType.UNION:
4535                operation: t.Type[exp.SetOperation] = exp.Union
4536            elif token_type == TokenType.EXCEPT:
4537                operation = exp.Except
4538            else:
4539                operation = exp.Intersect
4540
4541            comments = self._prev.comments
4542
4543            if self._match(TokenType.DISTINCT):
4544                distinct: t.Optional[bool] = True
4545            elif self._match(TokenType.ALL):
4546                distinct = False
4547            else:
4548                distinct = self.dialect.SET_OP_DISTINCT_BY_DEFAULT[operation]
4549                if distinct is None:
4550                    self.raise_error(f"Expected DISTINCT or ALL for {operation.__name__}")
4551
4552            by_name = self._match_text_seq("BY", "NAME")
4553            expression = self._parse_select(nested=True, parse_set_operation=False)
4554
4555            this = self.expression(
4556                operation,
4557                comments=comments,
4558                this=this,
4559                distinct=distinct,
4560                by_name=by_name,
4561                expression=expression,
4562            )
4563
4564        if isinstance(this, exp.SetOperation) and self.MODIFIERS_ATTACHED_TO_SET_OP:
4565            expression = this.expression
4566
4567            if expression:
4568                for arg in self.SET_OP_MODIFIERS:
4569                    expr = expression.args.get(arg)
4570                    if expr:
4571                        this.set(arg, expr.pop())
4572
4573        return this
4574
4575    def _parse_expression(self) -> t.Optional[exp.Expression]:
4576        return self._parse_alias(self._parse_assignment())
4577
4578    def _parse_assignment(self) -> t.Optional[exp.Expression]:
4579        this = self._parse_disjunction()
4580        if not this and self._next and self._next.token_type in self.ASSIGNMENT:
4581            # This allows us to parse <non-identifier token> := <expr>
4582            this = exp.column(
4583                t.cast(str, self._advance_any(ignore_reserved=True) and self._prev.text)
4584            )
4585
4586        while self._match_set(self.ASSIGNMENT):
4587            if isinstance(this, exp.Column) and len(this.parts) == 1:
4588                this = this.this
4589
4590            this = self.expression(
4591                self.ASSIGNMENT[self._prev.token_type],
4592                this=this,
4593                comments=self._prev_comments,
4594                expression=self._parse_assignment(),
4595            )
4596
4597        return this
4598
4599    def _parse_disjunction(self) -> t.Optional[exp.Expression]:
4600        return self._parse_tokens(self._parse_conjunction, self.DISJUNCTION)
4601
4602    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
4603        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
4604
4605    def _parse_equality(self) -> t.Optional[exp.Expression]:
4606        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
4607
4608    def _parse_comparison(self) -> t.Optional[exp.Expression]:
4609        return self._parse_tokens(self._parse_range, self.COMPARISON)
4610
4611    def _parse_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4612        this = this or self._parse_bitwise()
4613        negate = self._match(TokenType.NOT)
4614
4615        if self._match_set(self.RANGE_PARSERS):
4616            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
4617            if not expression:
4618                return this
4619
4620            this = expression
4621        elif self._match(TokenType.ISNULL):
4622            this = self.expression(exp.Is, this=this, expression=exp.Null())
4623
4624        # Postgres supports ISNULL and NOTNULL for conditions.
4625        # https://blog.andreiavram.ro/postgresql-null-composite-type/
4626        if self._match(TokenType.NOTNULL):
4627            this = self.expression(exp.Is, this=this, expression=exp.Null())
4628            this = self.expression(exp.Not, this=this)
4629
4630        if negate:
4631            this = self._negate_range(this)
4632
4633        if self._match(TokenType.IS):
4634            this = self._parse_is(this)
4635
4636        return this
4637
4638    def _negate_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4639        if not this:
4640            return this
4641
4642        return self.expression(exp.Not, this=this)
4643
4644    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4645        index = self._index - 1
4646        negate = self._match(TokenType.NOT)
4647
4648        if self._match_text_seq("DISTINCT", "FROM"):
4649            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
4650            return self.expression(klass, this=this, expression=self._parse_bitwise())
4651
4652        if self._match(TokenType.JSON):
4653            kind = self._match_texts(self.IS_JSON_PREDICATE_KIND) and self._prev.text.upper()
4654
4655            if self._match_text_seq("WITH"):
4656                _with = True
4657            elif self._match_text_seq("WITHOUT"):
4658                _with = False
4659            else:
4660                _with = None
4661
4662            unique = self._match(TokenType.UNIQUE)
4663            self._match_text_seq("KEYS")
4664            expression: t.Optional[exp.Expression] = self.expression(
4665                exp.JSON, **{"this": kind, "with": _with, "unique": unique}
4666            )
4667        else:
4668            expression = self._parse_primary() or self._parse_null()
4669            if not expression:
4670                self._retreat(index)
4671                return None
4672
4673        this = self.expression(exp.Is, this=this, expression=expression)
4674        return self.expression(exp.Not, this=this) if negate else this
4675
4676    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
4677        unnest = self._parse_unnest(with_alias=False)
4678        if unnest:
4679            this = self.expression(exp.In, this=this, unnest=unnest)
4680        elif self._match_set((TokenType.L_PAREN, TokenType.L_BRACKET)):
4681            matched_l_paren = self._prev.token_type == TokenType.L_PAREN
4682            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
4683
4684            if len(expressions) == 1 and isinstance(expressions[0], exp.Query):
4685                this = self.expression(exp.In, this=this, query=expressions[0].subquery(copy=False))
4686            else:
4687                this = self.expression(exp.In, this=this, expressions=expressions)
4688
4689            if matched_l_paren:
4690                self._match_r_paren(this)
4691            elif not self._match(TokenType.R_BRACKET, expression=this):
4692                self.raise_error("Expecting ]")
4693        else:
4694            this = self.expression(exp.In, this=this, field=self._parse_column())
4695
4696        return this
4697
4698    def _parse_between(self, this: t.Optional[exp.Expression]) -> exp.Between:
4699        low = self._parse_bitwise()
4700        self._match(TokenType.AND)
4701        high = self._parse_bitwise()
4702        return self.expression(exp.Between, this=this, low=low, high=high)
4703
4704    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4705        if not self._match(TokenType.ESCAPE):
4706            return this
4707        return self.expression(exp.Escape, this=this, expression=self._parse_string())
4708
4709    def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Add | exp.Interval]:
4710        index = self._index
4711
4712        if not self._match(TokenType.INTERVAL) and match_interval:
4713            return None
4714
4715        if self._match(TokenType.STRING, advance=False):
4716            this = self._parse_primary()
4717        else:
4718            this = self._parse_term()
4719
4720        if not this or (
4721            isinstance(this, exp.Column)
4722            and not this.table
4723            and not this.this.quoted
4724            and this.name.upper() == "IS"
4725        ):
4726            self._retreat(index)
4727            return None
4728
4729        unit = self._parse_function() or (
4730            not self._match(TokenType.ALIAS, advance=False)
4731            and self._parse_var(any_token=True, upper=True)
4732        )
4733
4734        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
4735        # each INTERVAL expression into this canonical form so it's easy to transpile
4736        if this and this.is_number:
4737            this = exp.Literal.string(this.to_py())
4738        elif this and this.is_string:
4739            parts = exp.INTERVAL_STRING_RE.findall(this.name)
4740            if parts and unit:
4741                # Unconsume the eagerly-parsed unit, since the real unit was part of the string
4742                unit = None
4743                self._retreat(self._index - 1)
4744
4745            if len(parts) == 1:
4746                this = exp.Literal.string(parts[0][0])
4747                unit = self.expression(exp.Var, this=parts[0][1].upper())
4748        if self.INTERVAL_SPANS and self._match_text_seq("TO"):
4749            unit = self.expression(
4750                exp.IntervalSpan, this=unit, expression=self._parse_var(any_token=True, upper=True)
4751            )
4752
4753        interval = self.expression(exp.Interval, this=this, unit=unit)
4754
4755        index = self._index
4756        self._match(TokenType.PLUS)
4757
4758        # Convert INTERVAL 'val_1' unit_1 [+] ... [+] 'val_n' unit_n into a sum of intervals
4759        if self._match_set((TokenType.STRING, TokenType.NUMBER), advance=False):
4760            return self.expression(
4761                exp.Add, this=interval, expression=self._parse_interval(match_interval=False)
4762            )
4763
4764        self._retreat(index)
4765        return interval
4766
4767    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
4768        this = self._parse_term()
4769
4770        while True:
4771            if self._match_set(self.BITWISE):
4772                this = self.expression(
4773                    self.BITWISE[self._prev.token_type],
4774                    this=this,
4775                    expression=self._parse_term(),
4776                )
4777            elif self.dialect.DPIPE_IS_STRING_CONCAT and self._match(TokenType.DPIPE):
4778                this = self.expression(
4779                    exp.DPipe,
4780                    this=this,
4781                    expression=self._parse_term(),
4782                    safe=not self.dialect.STRICT_STRING_CONCAT,
4783                )
4784            elif self._match(TokenType.DQMARK):
4785                this = self.expression(
4786                    exp.Coalesce, this=this, expressions=ensure_list(self._parse_term())
4787                )
4788            elif self._match_pair(TokenType.LT, TokenType.LT):
4789                this = self.expression(
4790                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
4791                )
4792            elif self._match_pair(TokenType.GT, TokenType.GT):
4793                this = self.expression(
4794                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
4795                )
4796            else:
4797                break
4798
4799        return this
4800
4801    def _parse_term(self) -> t.Optional[exp.Expression]:
4802        this = self._parse_factor()
4803
4804        while self._match_set(self.TERM):
4805            klass = self.TERM[self._prev.token_type]
4806            comments = self._prev_comments
4807            expression = self._parse_factor()
4808
4809            this = self.expression(klass, this=this, comments=comments, expression=expression)
4810
4811            if isinstance(this, exp.Collate):
4812                expr = this.expression
4813
4814                # Preserve collations such as pg_catalog."default" (Postgres) as columns, otherwise
4815                # fallback to Identifier / Var
4816                if isinstance(expr, exp.Column) and len(expr.parts) == 1:
4817                    ident = expr.this
4818                    if isinstance(ident, exp.Identifier):
4819                        this.set("expression", ident if ident.quoted else exp.var(ident.name))
4820
4821        return this
4822
4823    def _parse_factor(self) -> t.Optional[exp.Expression]:
4824        parse_method = self._parse_exponent if self.EXPONENT else self._parse_unary
4825        this = parse_method()
4826
4827        while self._match_set(self.FACTOR):
4828            klass = self.FACTOR[self._prev.token_type]
4829            comments = self._prev_comments
4830            expression = parse_method()
4831
4832            if not expression and klass is exp.IntDiv and self._prev.text.isalpha():
4833                self._retreat(self._index - 1)
4834                return this
4835
4836            this = self.expression(klass, this=this, comments=comments, expression=expression)
4837
4838            if isinstance(this, exp.Div):
4839                this.args["typed"] = self.dialect.TYPED_DIVISION
4840                this.args["safe"] = self.dialect.SAFE_DIVISION
4841
4842        return this
4843
4844    def _parse_exponent(self) -> t.Optional[exp.Expression]:
4845        return self._parse_tokens(self._parse_unary, self.EXPONENT)
4846
4847    def _parse_unary(self) -> t.Optional[exp.Expression]:
4848        if self._match_set(self.UNARY_PARSERS):
4849            return self.UNARY_PARSERS[self._prev.token_type](self)
4850        return self._parse_at_time_zone(self._parse_type())
4851
4852    def _parse_type(
4853        self, parse_interval: bool = True, fallback_to_identifier: bool = False
4854    ) -> t.Optional[exp.Expression]:
4855        interval = parse_interval and self._parse_interval()
4856        if interval:
4857            return interval
4858
4859        index = self._index
4860        data_type = self._parse_types(check_func=True, allow_identifiers=False)
4861
4862        # parse_types() returns a Cast if we parsed BQ's inline constructor <type>(<values>) e.g.
4863        # STRUCT<a INT, b STRING>(1, 'foo'), which is canonicalized to CAST(<values> AS <type>)
4864        if isinstance(data_type, exp.Cast):
4865            # This constructor can contain ops directly after it, for instance struct unnesting:
4866            # STRUCT<a INT, b STRING>(1, 'foo').* --> CAST(STRUCT(1, 'foo') AS STRUCT<a iNT, b STRING).*
4867            return self._parse_column_ops(data_type)
4868
4869        if data_type:
4870            index2 = self._index
4871            this = self._parse_primary()
4872
4873            if isinstance(this, exp.Literal):
4874                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
4875                if parser:
4876                    return parser(self, this, data_type)
4877
4878                return self.expression(exp.Cast, this=this, to=data_type)
4879
4880            # The expressions arg gets set by the parser when we have something like DECIMAL(38, 0)
4881            # in the input SQL. In that case, we'll produce these tokens: DECIMAL ( 38 , 0 )
4882            #
4883            # If the index difference here is greater than 1, that means the parser itself must have
4884            # consumed additional tokens such as the DECIMAL scale and precision in the above example.
4885            #
4886            # If it's not greater than 1, then it must be 1, because we've consumed at least the type
4887            # keyword, meaning that the expressions arg of the DataType must have gotten set by a
4888            # callable in the TYPE_CONVERTERS mapping. For example, Snowflake converts DECIMAL to
4889            # DECIMAL(38, 0)) in order to facilitate the data type's transpilation.
4890            #
4891            # In these cases, we don't really want to return the converted type, but instead retreat
4892            # and try to parse a Column or Identifier in the section below.
4893            if data_type.expressions and index2 - index > 1:
4894                self._retreat(index2)
4895                return self._parse_column_ops(data_type)
4896
4897            self._retreat(index)
4898
4899        if fallback_to_identifier:
4900            return self._parse_id_var()
4901
4902        this = self._parse_column()
4903        return this and self._parse_column_ops(this)
4904
4905    def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
4906        this = self._parse_type()
4907        if not this:
4908            return None
4909
4910        if isinstance(this, exp.Column) and not this.table:
4911            this = exp.var(this.name.upper())
4912
4913        return self.expression(
4914            exp.DataTypeParam, this=this, expression=self._parse_var(any_token=True)
4915        )
4916
4917    def _parse_types(
4918        self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
4919    ) -> t.Optional[exp.Expression]:
4920        index = self._index
4921
4922        this: t.Optional[exp.Expression] = None
4923        prefix = self._match_text_seq("SYSUDTLIB", ".")
4924
4925        if not self._match_set(self.TYPE_TOKENS):
4926            identifier = allow_identifiers and self._parse_id_var(
4927                any_token=False, tokens=(TokenType.VAR,)
4928            )
4929            if isinstance(identifier, exp.Identifier):
4930                tokens = self.dialect.tokenize(identifier.sql(dialect=self.dialect))
4931
4932                if len(tokens) != 1:
4933                    self.raise_error("Unexpected identifier", self._prev)
4934
4935                if tokens[0].token_type in self.TYPE_TOKENS:
4936                    self._prev = tokens[0]
4937                elif self.dialect.SUPPORTS_USER_DEFINED_TYPES:
4938                    type_name = identifier.name
4939
4940                    while self._match(TokenType.DOT):
4941                        type_name = f"{type_name}.{self._advance_any() and self._prev.text}"
4942
4943                    this = exp.DataType.build(type_name, udt=True)
4944                else:
4945                    self._retreat(self._index - 1)
4946                    return None
4947            else:
4948                return None
4949
4950        type_token = self._prev.token_type
4951
4952        if type_token == TokenType.PSEUDO_TYPE:
4953            return self.expression(exp.PseudoType, this=self._prev.text.upper())
4954
4955        if type_token == TokenType.OBJECT_IDENTIFIER:
4956            return self.expression(exp.ObjectIdentifier, this=self._prev.text.upper())
4957
4958        # https://materialize.com/docs/sql/types/map/
4959        if type_token == TokenType.MAP and self._match(TokenType.L_BRACKET):
4960            key_type = self._parse_types(
4961                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4962            )
4963            if not self._match(TokenType.FARROW):
4964                self._retreat(index)
4965                return None
4966
4967            value_type = self._parse_types(
4968                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4969            )
4970            if not self._match(TokenType.R_BRACKET):
4971                self._retreat(index)
4972                return None
4973
4974            return exp.DataType(
4975                this=exp.DataType.Type.MAP,
4976                expressions=[key_type, value_type],
4977                nested=True,
4978                prefix=prefix,
4979            )
4980
4981        nested = type_token in self.NESTED_TYPE_TOKENS
4982        is_struct = type_token in self.STRUCT_TYPE_TOKENS
4983        is_aggregate = type_token in self.AGGREGATE_TYPE_TOKENS
4984        expressions = None
4985        maybe_func = False
4986
4987        if self._match(TokenType.L_PAREN):
4988            if is_struct:
4989                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
4990            elif nested:
4991                expressions = self._parse_csv(
4992                    lambda: self._parse_types(
4993                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4994                    )
4995                )
4996                if type_token == TokenType.NULLABLE and len(expressions) == 1:
4997                    this = expressions[0]
4998                    this.set("nullable", True)
4999                    self._match_r_paren()
5000                    return this
5001            elif type_token in self.ENUM_TYPE_TOKENS:
5002                expressions = self._parse_csv(self._parse_equality)
5003            elif is_aggregate:
5004                func_or_ident = self._parse_function(anonymous=True) or self._parse_id_var(
5005                    any_token=False, tokens=(TokenType.VAR,)
5006                )
5007                if not func_or_ident or not self._match(TokenType.COMMA):
5008                    return None
5009                expressions = self._parse_csv(
5010                    lambda: self._parse_types(
5011                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
5012                    )
5013                )
5014                expressions.insert(0, func_or_ident)
5015            else:
5016                expressions = self._parse_csv(self._parse_type_size)
5017
5018                # https://docs.snowflake.com/en/sql-reference/data-types-vector
5019                if type_token == TokenType.VECTOR and len(expressions) == 2:
5020                    expressions[0] = exp.DataType.build(expressions[0].name, dialect=self.dialect)
5021
5022            if not expressions or not self._match(TokenType.R_PAREN):
5023                self._retreat(index)
5024                return None
5025
5026            maybe_func = True
5027
5028        values: t.Optional[t.List[exp.Expression]] = None
5029
5030        if nested and self._match(TokenType.LT):
5031            if is_struct:
5032                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
5033            else:
5034                expressions = self._parse_csv(
5035                    lambda: self._parse_types(
5036                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
5037                    )
5038                )
5039
5040            if not self._match(TokenType.GT):
5041                self.raise_error("Expecting >")
5042
5043            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
5044                values = self._parse_csv(self._parse_assignment)
5045                if not values and is_struct:
5046                    values = None
5047                    self._retreat(self._index - 1)
5048                else:
5049                    self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
5050
5051        if type_token in self.TIMESTAMPS:
5052            if self._match_text_seq("WITH", "TIME", "ZONE"):
5053                maybe_func = False
5054                tz_type = (
5055                    exp.DataType.Type.TIMETZ
5056                    if type_token in self.TIMES
5057                    else exp.DataType.Type.TIMESTAMPTZ
5058                )
5059                this = exp.DataType(this=tz_type, expressions=expressions)
5060            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
5061                maybe_func = False
5062                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
5063            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
5064                maybe_func = False
5065        elif type_token == TokenType.INTERVAL:
5066            unit = self._parse_var(upper=True)
5067            if unit:
5068                if self._match_text_seq("TO"):
5069                    unit = exp.IntervalSpan(this=unit, expression=self._parse_var(upper=True))
5070
5071                this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
5072            else:
5073                this = self.expression(exp.DataType, this=exp.DataType.Type.INTERVAL)
5074
5075        if maybe_func and check_func:
5076            index2 = self._index
5077            peek = self._parse_string()
5078
5079            if not peek:
5080                self._retreat(index)
5081                return None
5082
5083            self._retreat(index2)
5084
5085        if not this:
5086            if self._match_text_seq("UNSIGNED"):
5087                unsigned_type_token = self.SIGNED_TO_UNSIGNED_TYPE_TOKEN.get(type_token)
5088                if not unsigned_type_token:
5089                    self.raise_error(f"Cannot convert {type_token.value} to unsigned.")
5090
5091                type_token = unsigned_type_token or type_token
5092
5093            this = exp.DataType(
5094                this=exp.DataType.Type[type_token.value],
5095                expressions=expressions,
5096                nested=nested,
5097                prefix=prefix,
5098            )
5099
5100            # Empty arrays/structs are allowed
5101            if values is not None:
5102                cls = exp.Struct if is_struct else exp.Array
5103                this = exp.cast(cls(expressions=values), this, copy=False)
5104
5105        elif expressions:
5106            this.set("expressions", expressions)
5107
5108        # https://materialize.com/docs/sql/types/list/#type-name
5109        while self._match(TokenType.LIST):
5110            this = exp.DataType(this=exp.DataType.Type.LIST, expressions=[this], nested=True)
5111
5112        index = self._index
5113
5114        # Postgres supports the INT ARRAY[3] syntax as a synonym for INT[3]
5115        matched_array = self._match(TokenType.ARRAY)
5116
5117        while self._curr:
5118            datatype_token = self._prev.token_type
5119            matched_l_bracket = self._match(TokenType.L_BRACKET)
5120            if not matched_l_bracket and not matched_array:
5121                break
5122
5123            matched_array = False
5124            values = self._parse_csv(self._parse_assignment) or None
5125            if (
5126                values
5127                and not schema
5128                and (
5129                    not self.dialect.SUPPORTS_FIXED_SIZE_ARRAYS or datatype_token == TokenType.ARRAY
5130                )
5131            ):
5132                # Retreating here means that we should not parse the following values as part of the data type, e.g. in DuckDB
5133                # 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
5134                self._retreat(index)
5135                break
5136
5137            this = exp.DataType(
5138                this=exp.DataType.Type.ARRAY, expressions=[this], values=values, nested=True
5139            )
5140            self._match(TokenType.R_BRACKET)
5141
5142        if self.TYPE_CONVERTERS and isinstance(this.this, exp.DataType.Type):
5143            converter = self.TYPE_CONVERTERS.get(this.this)
5144            if converter:
5145                this = converter(t.cast(exp.DataType, this))
5146
5147        return this
5148
5149    def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
5150        index = self._index
5151
5152        if (
5153            self._curr
5154            and self._next
5155            and self._curr.token_type in self.TYPE_TOKENS
5156            and self._next.token_type in self.TYPE_TOKENS
5157        ):
5158            # Takes care of special cases like `STRUCT<list ARRAY<...>>` where the identifier is also a
5159            # type token. Without this, the list will be parsed as a type and we'll eventually crash
5160            this = self._parse_id_var()
5161        else:
5162            this = (
5163                self._parse_type(parse_interval=False, fallback_to_identifier=True)
5164                or self._parse_id_var()
5165            )
5166
5167        self._match(TokenType.COLON)
5168
5169        if (
5170            type_required
5171            and not isinstance(this, exp.DataType)
5172            and not self._match_set(self.TYPE_TOKENS, advance=False)
5173        ):
5174            self._retreat(index)
5175            return self._parse_types()
5176
5177        return self._parse_column_def(this)
5178
5179    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5180        if not self._match_text_seq("AT", "TIME", "ZONE"):
5181            return this
5182        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
5183
5184    def _parse_column(self) -> t.Optional[exp.Expression]:
5185        this = self._parse_column_reference()
5186        column = self._parse_column_ops(this) if this else self._parse_bracket(this)
5187
5188        if self.dialect.SUPPORTS_COLUMN_JOIN_MARKS and column:
5189            column.set("join_mark", self._match(TokenType.JOIN_MARKER))
5190
5191        return column
5192
5193    def _parse_column_reference(self) -> t.Optional[exp.Expression]:
5194        this = self._parse_field()
5195        if (
5196            not this
5197            and self._match(TokenType.VALUES, advance=False)
5198            and self.VALUES_FOLLOWED_BY_PAREN
5199            and (not self._next or self._next.token_type != TokenType.L_PAREN)
5200        ):
5201            this = self._parse_id_var()
5202
5203        if isinstance(this, exp.Identifier):
5204            # We bubble up comments from the Identifier to the Column
5205            this = self.expression(exp.Column, comments=this.pop_comments(), this=this)
5206
5207        return this
5208
5209    def _parse_colon_as_variant_extract(
5210        self, this: t.Optional[exp.Expression]
5211    ) -> t.Optional[exp.Expression]:
5212        casts = []
5213        json_path = []
5214        escape = None
5215
5216        while self._match(TokenType.COLON):
5217            start_index = self._index
5218
5219            # Snowflake allows reserved keywords as json keys but advance_any() excludes TokenType.SELECT from any_tokens=True
5220            path = self._parse_column_ops(
5221                self._parse_field(any_token=True, tokens=(TokenType.SELECT,))
5222            )
5223
5224            # The cast :: operator has a lower precedence than the extraction operator :, so
5225            # we rearrange the AST appropriately to avoid casting the JSON path
5226            while isinstance(path, exp.Cast):
5227                casts.append(path.to)
5228                path = path.this
5229
5230            if casts:
5231                dcolon_offset = next(
5232                    i
5233                    for i, t in enumerate(self._tokens[start_index:])
5234                    if t.token_type == TokenType.DCOLON
5235                )
5236                end_token = self._tokens[start_index + dcolon_offset - 1]
5237            else:
5238                end_token = self._prev
5239
5240            if path:
5241                # Escape single quotes from Snowflake's colon extraction (e.g. col:"a'b") as
5242                # it'll roundtrip to a string literal in GET_PATH
5243                if isinstance(path, exp.Identifier) and path.quoted:
5244                    escape = True
5245
5246                json_path.append(self._find_sql(self._tokens[start_index], end_token))
5247
5248        # The VARIANT extract in Snowflake/Databricks is parsed as a JSONExtract; Snowflake uses the json_path in GET_PATH() while
5249        # Databricks transforms it back to the colon/dot notation
5250        if json_path:
5251            json_path_expr = self.dialect.to_json_path(exp.Literal.string(".".join(json_path)))
5252
5253            if json_path_expr:
5254                json_path_expr.set("escape", escape)
5255
5256            this = self.expression(
5257                exp.JSONExtract,
5258                this=this,
5259                expression=json_path_expr,
5260                variant_extract=True,
5261            )
5262
5263            while casts:
5264                this = self.expression(exp.Cast, this=this, to=casts.pop())
5265
5266        return this
5267
5268    def _parse_dcolon(self) -> t.Optional[exp.Expression]:
5269        return self._parse_types()
5270
5271    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5272        this = self._parse_bracket(this)
5273
5274        while self._match_set(self.COLUMN_OPERATORS):
5275            op_token = self._prev.token_type
5276            op = self.COLUMN_OPERATORS.get(op_token)
5277
5278            if op_token == TokenType.DCOLON:
5279                field = self._parse_dcolon()
5280                if not field:
5281                    self.raise_error("Expected type")
5282            elif op and self._curr:
5283                field = self._parse_column_reference() or self._parse_bracket()
5284            else:
5285                field = self._parse_field(any_token=True, anonymous_func=True)
5286
5287            if isinstance(field, (exp.Func, exp.Window)) and this:
5288                # BQ & snowflake allow function calls like x.y.count(...), SAFE.SUBSTR(...) etc
5289                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
5290                this = exp.replace_tree(
5291                    this,
5292                    lambda n: (
5293                        self.expression(exp.Dot, this=n.args.get("table"), expression=n.this)
5294                        if n.table
5295                        else n.this
5296                    )
5297                    if isinstance(n, exp.Column)
5298                    else n,
5299                )
5300
5301            if op:
5302                this = op(self, this, field)
5303            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
5304                this = self.expression(
5305                    exp.Column,
5306                    comments=this.comments,
5307                    this=field,
5308                    table=this.this,
5309                    db=this.args.get("table"),
5310                    catalog=this.args.get("db"),
5311                )
5312            elif isinstance(field, exp.Window):
5313                # Move the exp.Dot's to the window's function
5314                window_func = self.expression(exp.Dot, this=this, expression=field.this)
5315                field.set("this", window_func)
5316                this = field
5317            else:
5318                this = self.expression(exp.Dot, this=this, expression=field)
5319
5320            if field and field.comments:
5321                t.cast(exp.Expression, this).add_comments(field.pop_comments())
5322
5323            this = self._parse_bracket(this)
5324
5325        return self._parse_colon_as_variant_extract(this) if self.COLON_IS_VARIANT_EXTRACT else this
5326
5327    def _parse_primary(self) -> t.Optional[exp.Expression]:
5328        if self._match_set(self.PRIMARY_PARSERS):
5329            token_type = self._prev.token_type
5330            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
5331
5332            if token_type == TokenType.STRING:
5333                expressions = [primary]
5334                while self._match(TokenType.STRING):
5335                    expressions.append(exp.Literal.string(self._prev.text))
5336
5337                if len(expressions) > 1:
5338                    return self.expression(exp.Concat, expressions=expressions)
5339
5340            return primary
5341
5342        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
5343            return exp.Literal.number(f"0.{self._prev.text}")
5344
5345        if self._match(TokenType.L_PAREN):
5346            comments = self._prev_comments
5347            query = self._parse_select()
5348
5349            if query:
5350                expressions = [query]
5351            else:
5352                expressions = self._parse_expressions()
5353
5354            this = self._parse_query_modifiers(seq_get(expressions, 0))
5355
5356            if not this and self._match(TokenType.R_PAREN, advance=False):
5357                this = self.expression(exp.Tuple)
5358            elif isinstance(this, exp.UNWRAPPED_QUERIES):
5359                this = self._parse_subquery(this=this, parse_alias=False)
5360            elif isinstance(this, exp.Subquery):
5361                this = self._parse_subquery(
5362                    this=self._parse_set_operations(this), parse_alias=False
5363                )
5364            elif len(expressions) > 1 or self._prev.token_type == TokenType.COMMA:
5365                this = self.expression(exp.Tuple, expressions=expressions)
5366            else:
5367                this = self.expression(exp.Paren, this=this)
5368
5369            if this:
5370                this.add_comments(comments)
5371
5372            self._match_r_paren(expression=this)
5373            return this
5374
5375        return None
5376
5377    def _parse_field(
5378        self,
5379        any_token: bool = False,
5380        tokens: t.Optional[t.Collection[TokenType]] = None,
5381        anonymous_func: bool = False,
5382    ) -> t.Optional[exp.Expression]:
5383        if anonymous_func:
5384            field = (
5385                self._parse_function(anonymous=anonymous_func, any_token=any_token)
5386                or self._parse_primary()
5387            )
5388        else:
5389            field = self._parse_primary() or self._parse_function(
5390                anonymous=anonymous_func, any_token=any_token
5391            )
5392        return field or self._parse_id_var(any_token=any_token, tokens=tokens)
5393
5394    def _parse_function(
5395        self,
5396        functions: t.Optional[t.Dict[str, t.Callable]] = None,
5397        anonymous: bool = False,
5398        optional_parens: bool = True,
5399        any_token: bool = False,
5400    ) -> t.Optional[exp.Expression]:
5401        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
5402        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
5403        fn_syntax = False
5404        if (
5405            self._match(TokenType.L_BRACE, advance=False)
5406            and self._next
5407            and self._next.text.upper() == "FN"
5408        ):
5409            self._advance(2)
5410            fn_syntax = True
5411
5412        func = self._parse_function_call(
5413            functions=functions,
5414            anonymous=anonymous,
5415            optional_parens=optional_parens,
5416            any_token=any_token,
5417        )
5418
5419        if fn_syntax:
5420            self._match(TokenType.R_BRACE)
5421
5422        return func
5423
5424    def _parse_function_call(
5425        self,
5426        functions: t.Optional[t.Dict[str, t.Callable]] = None,
5427        anonymous: bool = False,
5428        optional_parens: bool = True,
5429        any_token: bool = False,
5430    ) -> t.Optional[exp.Expression]:
5431        if not self._curr:
5432            return None
5433
5434        comments = self._curr.comments
5435        token_type = self._curr.token_type
5436        this = self._curr.text
5437        upper = this.upper()
5438
5439        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
5440        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
5441            self._advance()
5442            return self._parse_window(parser(self))
5443
5444        if not self._next or self._next.token_type != TokenType.L_PAREN:
5445            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
5446                self._advance()
5447                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
5448
5449            return None
5450
5451        if any_token:
5452            if token_type in self.RESERVED_TOKENS:
5453                return None
5454        elif token_type not in self.FUNC_TOKENS:
5455            return None
5456
5457        self._advance(2)
5458
5459        parser = self.FUNCTION_PARSERS.get(upper)
5460        if parser and not anonymous:
5461            this = parser(self)
5462        else:
5463            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
5464
5465            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
5466                this = self.expression(
5467                    subquery_predicate, comments=comments, this=self._parse_select()
5468                )
5469                self._match_r_paren()
5470                return this
5471
5472            if functions is None:
5473                functions = self.FUNCTIONS
5474
5475            function = functions.get(upper)
5476            known_function = function and not anonymous
5477
5478            alias = not known_function or upper in self.FUNCTIONS_WITH_ALIASED_ARGS
5479            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
5480
5481            post_func_comments = self._curr and self._curr.comments
5482            if known_function and post_func_comments:
5483                # If the user-inputted comment "/* sqlglot.anonymous */" is following the function
5484                # call we'll construct it as exp.Anonymous, even if it's "known"
5485                if any(
5486                    comment.lstrip().startswith(exp.SQLGLOT_ANONYMOUS)
5487                    for comment in post_func_comments
5488                ):
5489                    known_function = False
5490
5491            if alias and known_function:
5492                args = self._kv_to_prop_eq(args)
5493
5494            if known_function:
5495                func_builder = t.cast(t.Callable, function)
5496
5497                if "dialect" in func_builder.__code__.co_varnames:
5498                    func = func_builder(args, dialect=self.dialect)
5499                else:
5500                    func = func_builder(args)
5501
5502                func = self.validate_expression(func, args)
5503                if self.dialect.PRESERVE_ORIGINAL_NAMES:
5504                    func.meta["name"] = this
5505
5506                this = func
5507            else:
5508                if token_type == TokenType.IDENTIFIER:
5509                    this = exp.Identifier(this=this, quoted=True)
5510                this = self.expression(exp.Anonymous, this=this, expressions=args)
5511
5512        if isinstance(this, exp.Expression):
5513            this.add_comments(comments)
5514
5515        self._match_r_paren(this)
5516        return self._parse_window(this)
5517
5518    def _to_prop_eq(self, expression: exp.Expression, index: int) -> exp.Expression:
5519        return expression
5520
5521    def _kv_to_prop_eq(self, expressions: t.List[exp.Expression]) -> t.List[exp.Expression]:
5522        transformed = []
5523
5524        for index, e in enumerate(expressions):
5525            if isinstance(e, self.KEY_VALUE_DEFINITIONS):
5526                if isinstance(e, exp.Alias):
5527                    e = self.expression(exp.PropertyEQ, this=e.args.get("alias"), expression=e.this)
5528
5529                if not isinstance(e, exp.PropertyEQ):
5530                    e = self.expression(
5531                        exp.PropertyEQ, this=exp.to_identifier(e.this.name), expression=e.expression
5532                    )
5533
5534                if isinstance(e.this, exp.Column):
5535                    e.this.replace(e.this.this)
5536            else:
5537                e = self._to_prop_eq(e, index)
5538
5539            transformed.append(e)
5540
5541        return transformed
5542
5543    def _parse_user_defined_function_expression(self) -> t.Optional[exp.Expression]:
5544        return self._parse_statement()
5545
5546    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
5547        return self._parse_column_def(self._parse_id_var())
5548
5549    def _parse_user_defined_function(
5550        self, kind: t.Optional[TokenType] = None
5551    ) -> t.Optional[exp.Expression]:
5552        this = self._parse_id_var()
5553
5554        while self._match(TokenType.DOT):
5555            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
5556
5557        if not self._match(TokenType.L_PAREN):
5558            return this
5559
5560        expressions = self._parse_csv(self._parse_function_parameter)
5561        self._match_r_paren()
5562        return self.expression(
5563            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
5564        )
5565
5566    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
5567        literal = self._parse_primary()
5568        if literal:
5569            return self.expression(exp.Introducer, this=token.text, expression=literal)
5570
5571        return self.expression(exp.Identifier, this=token.text)
5572
5573    def _parse_session_parameter(self) -> exp.SessionParameter:
5574        kind = None
5575        this = self._parse_id_var() or self._parse_primary()
5576
5577        if this and self._match(TokenType.DOT):
5578            kind = this.name
5579            this = self._parse_var() or self._parse_primary()
5580
5581        return self.expression(exp.SessionParameter, this=this, kind=kind)
5582
5583    def _parse_lambda_arg(self) -> t.Optional[exp.Expression]:
5584        return self._parse_id_var()
5585
5586    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
5587        index = self._index
5588
5589        if self._match(TokenType.L_PAREN):
5590            expressions = t.cast(
5591                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_lambda_arg)
5592            )
5593
5594            if not self._match(TokenType.R_PAREN):
5595                self._retreat(index)
5596        else:
5597            expressions = [self._parse_lambda_arg()]
5598
5599        if self._match_set(self.LAMBDAS):
5600            return self.LAMBDAS[self._prev.token_type](self, expressions)
5601
5602        self._retreat(index)
5603
5604        this: t.Optional[exp.Expression]
5605
5606        if self._match(TokenType.DISTINCT):
5607            this = self.expression(
5608                exp.Distinct, expressions=self._parse_csv(self._parse_assignment)
5609            )
5610        else:
5611            this = self._parse_select_or_expression(alias=alias)
5612
5613        return self._parse_limit(
5614            self._parse_order(self._parse_having_max(self._parse_respect_or_ignore_nulls(this)))
5615        )
5616
5617    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
5618        index = self._index
5619        if not self._match(TokenType.L_PAREN):
5620            return this
5621
5622        # Disambiguate between schema and subquery/CTE, e.g. in INSERT INTO table (<expr>),
5623        # expr can be of both types
5624        if self._match_set(self.SELECT_START_TOKENS):
5625            self._retreat(index)
5626            return this
5627        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
5628        self._match_r_paren()
5629        return self.expression(exp.Schema, this=this, expressions=args)
5630
5631    def _parse_field_def(self) -> t.Optional[exp.Expression]:
5632        return self._parse_column_def(self._parse_field(any_token=True))
5633
5634    def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5635        # column defs are not really columns, they're identifiers
5636        if isinstance(this, exp.Column):
5637            this = this.this
5638
5639        kind = self._parse_types(schema=True)
5640
5641        if self._match_text_seq("FOR", "ORDINALITY"):
5642            return self.expression(exp.ColumnDef, this=this, ordinality=True)
5643
5644        constraints: t.List[exp.Expression] = []
5645
5646        if (not kind and self._match(TokenType.ALIAS)) or self._match_texts(
5647            ("ALIAS", "MATERIALIZED")
5648        ):
5649            persisted = self._prev.text.upper() == "MATERIALIZED"
5650            constraint_kind = exp.ComputedColumnConstraint(
5651                this=self._parse_assignment(),
5652                persisted=persisted or self._match_text_seq("PERSISTED"),
5653                not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
5654            )
5655            constraints.append(self.expression(exp.ColumnConstraint, kind=constraint_kind))
5656        elif (
5657            kind
5658            and self._match(TokenType.ALIAS, advance=False)
5659            and (
5660                not self.WRAPPED_TRANSFORM_COLUMN_CONSTRAINT
5661                or (self._next and self._next.token_type == TokenType.L_PAREN)
5662            )
5663        ):
5664            self._advance()
5665            constraints.append(
5666                self.expression(
5667                    exp.ColumnConstraint,
5668                    kind=exp.TransformColumnConstraint(this=self._parse_disjunction()),
5669                )
5670            )
5671
5672        while True:
5673            constraint = self._parse_column_constraint()
5674            if not constraint:
5675                break
5676            constraints.append(constraint)
5677
5678        if not kind and not constraints:
5679            return this
5680
5681        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
5682
5683    def _parse_auto_increment(
5684        self,
5685    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
5686        start = None
5687        increment = None
5688
5689        if self._match(TokenType.L_PAREN, advance=False):
5690            args = self._parse_wrapped_csv(self._parse_bitwise)
5691            start = seq_get(args, 0)
5692            increment = seq_get(args, 1)
5693        elif self._match_text_seq("START"):
5694            start = self._parse_bitwise()
5695            self._match_text_seq("INCREMENT")
5696            increment = self._parse_bitwise()
5697
5698        if start and increment:
5699            return exp.GeneratedAsIdentityColumnConstraint(start=start, increment=increment)
5700
5701        return exp.AutoIncrementColumnConstraint()
5702
5703    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
5704        if not self._match_text_seq("REFRESH"):
5705            self._retreat(self._index - 1)
5706            return None
5707        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
5708
5709    def _parse_compress(self) -> exp.CompressColumnConstraint:
5710        if self._match(TokenType.L_PAREN, advance=False):
5711            return self.expression(
5712                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
5713            )
5714
5715        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
5716
5717    def _parse_generated_as_identity(
5718        self,
5719    ) -> (
5720        exp.GeneratedAsIdentityColumnConstraint
5721        | exp.ComputedColumnConstraint
5722        | exp.GeneratedAsRowColumnConstraint
5723    ):
5724        if self._match_text_seq("BY", "DEFAULT"):
5725            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
5726            this = self.expression(
5727                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
5728            )
5729        else:
5730            self._match_text_seq("ALWAYS")
5731            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
5732
5733        self._match(TokenType.ALIAS)
5734
5735        if self._match_text_seq("ROW"):
5736            start = self._match_text_seq("START")
5737            if not start:
5738                self._match(TokenType.END)
5739            hidden = self._match_text_seq("HIDDEN")
5740            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
5741
5742        identity = self._match_text_seq("IDENTITY")
5743
5744        if self._match(TokenType.L_PAREN):
5745            if self._match(TokenType.START_WITH):
5746                this.set("start", self._parse_bitwise())
5747            if self._match_text_seq("INCREMENT", "BY"):
5748                this.set("increment", self._parse_bitwise())
5749            if self._match_text_seq("MINVALUE"):
5750                this.set("minvalue", self._parse_bitwise())
5751            if self._match_text_seq("MAXVALUE"):
5752                this.set("maxvalue", self._parse_bitwise())
5753
5754            if self._match_text_seq("CYCLE"):
5755                this.set("cycle", True)
5756            elif self._match_text_seq("NO", "CYCLE"):
5757                this.set("cycle", False)
5758
5759            if not identity:
5760                this.set("expression", self._parse_range())
5761            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
5762                args = self._parse_csv(self._parse_bitwise)
5763                this.set("start", seq_get(args, 0))
5764                this.set("increment", seq_get(args, 1))
5765
5766            self._match_r_paren()
5767
5768        return this
5769
5770    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
5771        self._match_text_seq("LENGTH")
5772        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
5773
5774    def _parse_not_constraint(self) -> t.Optional[exp.Expression]:
5775        if self._match_text_seq("NULL"):
5776            return self.expression(exp.NotNullColumnConstraint)
5777        if self._match_text_seq("CASESPECIFIC"):
5778            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
5779        if self._match_text_seq("FOR", "REPLICATION"):
5780            return self.expression(exp.NotForReplicationColumnConstraint)
5781
5782        # Unconsume the `NOT` token
5783        self._retreat(self._index - 1)
5784        return None
5785
5786    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
5787        this = self._match(TokenType.CONSTRAINT) and self._parse_id_var()
5788
5789        procedure_option_follows = (
5790            self._match(TokenType.WITH, advance=False)
5791            and self._next
5792            and self._next.text.upper() in self.PROCEDURE_OPTIONS
5793        )
5794
5795        if not procedure_option_follows and self._match_texts(self.CONSTRAINT_PARSERS):
5796            return self.expression(
5797                exp.ColumnConstraint,
5798                this=this,
5799                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
5800            )
5801
5802        return this
5803
5804    def _parse_constraint(self) -> t.Optional[exp.Expression]:
5805        if not self._match(TokenType.CONSTRAINT):
5806            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
5807
5808        return self.expression(
5809            exp.Constraint,
5810            this=self._parse_id_var(),
5811            expressions=self._parse_unnamed_constraints(),
5812        )
5813
5814    def _parse_unnamed_constraints(self) -> t.List[exp.Expression]:
5815        constraints = []
5816        while True:
5817            constraint = self._parse_unnamed_constraint() or self._parse_function()
5818            if not constraint:
5819                break
5820            constraints.append(constraint)
5821
5822        return constraints
5823
5824    def _parse_unnamed_constraint(
5825        self, constraints: t.Optional[t.Collection[str]] = None
5826    ) -> t.Optional[exp.Expression]:
5827        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
5828            constraints or self.CONSTRAINT_PARSERS
5829        ):
5830            return None
5831
5832        constraint = self._prev.text.upper()
5833        if constraint not in self.CONSTRAINT_PARSERS:
5834            self.raise_error(f"No parser found for schema constraint {constraint}.")
5835
5836        return self.CONSTRAINT_PARSERS[constraint](self)
5837
5838    def _parse_unique_key(self) -> t.Optional[exp.Expression]:
5839        return self._parse_id_var(any_token=False)
5840
5841    def _parse_unique(self) -> exp.UniqueColumnConstraint:
5842        self._match_text_seq("KEY")
5843        return self.expression(
5844            exp.UniqueColumnConstraint,
5845            nulls=self._match_text_seq("NULLS", "NOT", "DISTINCT"),
5846            this=self._parse_schema(self._parse_unique_key()),
5847            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
5848            on_conflict=self._parse_on_conflict(),
5849        )
5850
5851    def _parse_key_constraint_options(self) -> t.List[str]:
5852        options = []
5853        while True:
5854            if not self._curr:
5855                break
5856
5857            if self._match(TokenType.ON):
5858                action = None
5859                on = self._advance_any() and self._prev.text
5860
5861                if self._match_text_seq("NO", "ACTION"):
5862                    action = "NO ACTION"
5863                elif self._match_text_seq("CASCADE"):
5864                    action = "CASCADE"
5865                elif self._match_text_seq("RESTRICT"):
5866                    action = "RESTRICT"
5867                elif self._match_pair(TokenType.SET, TokenType.NULL):
5868                    action = "SET NULL"
5869                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
5870                    action = "SET DEFAULT"
5871                else:
5872                    self.raise_error("Invalid key constraint")
5873
5874                options.append(f"ON {on} {action}")
5875            else:
5876                var = self._parse_var_from_options(
5877                    self.KEY_CONSTRAINT_OPTIONS, raise_unmatched=False
5878                )
5879                if not var:
5880                    break
5881                options.append(var.name)
5882
5883        return options
5884
5885    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
5886        if match and not self._match(TokenType.REFERENCES):
5887            return None
5888
5889        expressions = None
5890        this = self._parse_table(schema=True)
5891        options = self._parse_key_constraint_options()
5892        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
5893
5894    def _parse_foreign_key(self) -> exp.ForeignKey:
5895        expressions = self._parse_wrapped_id_vars()
5896        reference = self._parse_references()
5897        options = {}
5898
5899        while self._match(TokenType.ON):
5900            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
5901                self.raise_error("Expected DELETE or UPDATE")
5902
5903            kind = self._prev.text.lower()
5904
5905            if self._match_text_seq("NO", "ACTION"):
5906                action = "NO ACTION"
5907            elif self._match(TokenType.SET):
5908                self._match_set((TokenType.NULL, TokenType.DEFAULT))
5909                action = "SET " + self._prev.text.upper()
5910            else:
5911                self._advance()
5912                action = self._prev.text.upper()
5913
5914            options[kind] = action
5915
5916        return self.expression(
5917            exp.ForeignKey,
5918            expressions=expressions,
5919            reference=reference,
5920            **options,  # type: ignore
5921        )
5922
5923    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
5924        return self._parse_ordered() or self._parse_field()
5925
5926    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
5927        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
5928            self._retreat(self._index - 1)
5929            return None
5930
5931        id_vars = self._parse_wrapped_id_vars()
5932        return self.expression(
5933            exp.PeriodForSystemTimeConstraint,
5934            this=seq_get(id_vars, 0),
5935            expression=seq_get(id_vars, 1),
5936        )
5937
5938    def _parse_primary_key(
5939        self, wrapped_optional: bool = False, in_props: bool = False
5940    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
5941        desc = (
5942            self._match_set((TokenType.ASC, TokenType.DESC))
5943            and self._prev.token_type == TokenType.DESC
5944        )
5945
5946        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
5947            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
5948
5949        expressions = self._parse_wrapped_csv(
5950            self._parse_primary_key_part, optional=wrapped_optional
5951        )
5952        options = self._parse_key_constraint_options()
5953        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
5954
5955    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
5956        return self._parse_slice(self._parse_alias(self._parse_assignment(), explicit=True))
5957
5958    def _parse_odbc_datetime_literal(self) -> exp.Expression:
5959        """
5960        Parses a datetime column in ODBC format. We parse the column into the corresponding
5961        types, for example `{d'yyyy-mm-dd'}` will be parsed as a `Date` column, exactly the
5962        same as we did for `DATE('yyyy-mm-dd')`.
5963
5964        Reference:
5965        https://learn.microsoft.com/en-us/sql/odbc/reference/develop-app/date-time-and-timestamp-literals
5966        """
5967        self._match(TokenType.VAR)
5968        exp_class = self.ODBC_DATETIME_LITERALS[self._prev.text.lower()]
5969        expression = self.expression(exp_class=exp_class, this=self._parse_string())
5970        if not self._match(TokenType.R_BRACE):
5971            self.raise_error("Expected }")
5972        return expression
5973
5974    def _parse_bracket(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
5975        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
5976            return this
5977
5978        bracket_kind = self._prev.token_type
5979        if (
5980            bracket_kind == TokenType.L_BRACE
5981            and self._curr
5982            and self._curr.token_type == TokenType.VAR
5983            and self._curr.text.lower() in self.ODBC_DATETIME_LITERALS
5984        ):
5985            return self._parse_odbc_datetime_literal()
5986
5987        expressions = self._parse_csv(
5988            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
5989        )
5990
5991        if bracket_kind == TokenType.L_BRACKET and not self._match(TokenType.R_BRACKET):
5992            self.raise_error("Expected ]")
5993        elif bracket_kind == TokenType.L_BRACE and not self._match(TokenType.R_BRACE):
5994            self.raise_error("Expected }")
5995
5996        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
5997        if bracket_kind == TokenType.L_BRACE:
5998            this = self.expression(exp.Struct, expressions=self._kv_to_prop_eq(expressions))
5999        elif not this:
6000            this = build_array_constructor(
6001                exp.Array, args=expressions, bracket_kind=bracket_kind, dialect=self.dialect
6002            )
6003        else:
6004            constructor_type = self.ARRAY_CONSTRUCTORS.get(this.name.upper())
6005            if constructor_type:
6006                return build_array_constructor(
6007                    constructor_type,
6008                    args=expressions,
6009                    bracket_kind=bracket_kind,
6010                    dialect=self.dialect,
6011                )
6012
6013            expressions = apply_index_offset(this, expressions, -self.dialect.INDEX_OFFSET)
6014            this = self.expression(exp.Bracket, this=this, expressions=expressions)
6015
6016        self._add_comments(this)
6017        return self._parse_bracket(this)
6018
6019    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
6020        if self._match(TokenType.COLON):
6021            return self.expression(exp.Slice, this=this, expression=self._parse_assignment())
6022        return this
6023
6024    def _parse_case(self) -> t.Optional[exp.Expression]:
6025        ifs = []
6026        default = None
6027
6028        comments = self._prev_comments
6029        expression = self._parse_assignment()
6030
6031        while self._match(TokenType.WHEN):
6032            this = self._parse_assignment()
6033            self._match(TokenType.THEN)
6034            then = self._parse_assignment()
6035            ifs.append(self.expression(exp.If, this=this, true=then))
6036
6037        if self._match(TokenType.ELSE):
6038            default = self._parse_assignment()
6039
6040        if not self._match(TokenType.END):
6041            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
6042                default = exp.column("interval")
6043            else:
6044                self.raise_error("Expected END after CASE", self._prev)
6045
6046        return self.expression(
6047            exp.Case, comments=comments, this=expression, ifs=ifs, default=default
6048        )
6049
6050    def _parse_if(self) -> t.Optional[exp.Expression]:
6051        if self._match(TokenType.L_PAREN):
6052            args = self._parse_csv(self._parse_assignment)
6053            this = self.validate_expression(exp.If.from_arg_list(args), args)
6054            self._match_r_paren()
6055        else:
6056            index = self._index - 1
6057
6058            if self.NO_PAREN_IF_COMMANDS and index == 0:
6059                return self._parse_as_command(self._prev)
6060
6061            condition = self._parse_assignment()
6062
6063            if not condition:
6064                self._retreat(index)
6065                return None
6066
6067            self._match(TokenType.THEN)
6068            true = self._parse_assignment()
6069            false = self._parse_assignment() if self._match(TokenType.ELSE) else None
6070            self._match(TokenType.END)
6071            this = self.expression(exp.If, this=condition, true=true, false=false)
6072
6073        return this
6074
6075    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
6076        if not self._match_text_seq("VALUE", "FOR"):
6077            self._retreat(self._index - 1)
6078            return None
6079
6080        return self.expression(
6081            exp.NextValueFor,
6082            this=self._parse_column(),
6083            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
6084        )
6085
6086    def _parse_extract(self) -> exp.Extract | exp.Anonymous:
6087        this = self._parse_function() or self._parse_var_or_string(upper=True)
6088
6089        if self._match(TokenType.FROM):
6090            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
6091
6092        if not self._match(TokenType.COMMA):
6093            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
6094
6095        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
6096
6097    def _parse_gap_fill(self) -> exp.GapFill:
6098        self._match(TokenType.TABLE)
6099        this = self._parse_table()
6100
6101        self._match(TokenType.COMMA)
6102        args = [this, *self._parse_csv(self._parse_lambda)]
6103
6104        gap_fill = exp.GapFill.from_arg_list(args)
6105        return self.validate_expression(gap_fill, args)
6106
6107    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
6108        this = self._parse_assignment()
6109
6110        if not self._match(TokenType.ALIAS):
6111            if self._match(TokenType.COMMA):
6112                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
6113
6114            self.raise_error("Expected AS after CAST")
6115
6116        fmt = None
6117        to = self._parse_types()
6118
6119        if self._match(TokenType.FORMAT):
6120            fmt_string = self._parse_string()
6121            fmt = self._parse_at_time_zone(fmt_string)
6122
6123            if not to:
6124                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
6125            if to.this in exp.DataType.TEMPORAL_TYPES:
6126                this = self.expression(
6127                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
6128                    this=this,
6129                    format=exp.Literal.string(
6130                        format_time(
6131                            fmt_string.this if fmt_string else "",
6132                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
6133                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
6134                        )
6135                    ),
6136                    safe=safe,
6137                )
6138
6139                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
6140                    this.set("zone", fmt.args["zone"])
6141                return this
6142        elif not to:
6143            self.raise_error("Expected TYPE after CAST")
6144        elif isinstance(to, exp.Identifier):
6145            to = exp.DataType.build(to.name, udt=True)
6146        elif to.this == exp.DataType.Type.CHAR:
6147            if self._match(TokenType.CHARACTER_SET):
6148                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
6149
6150        return self.expression(
6151            exp.Cast if strict else exp.TryCast,
6152            this=this,
6153            to=to,
6154            format=fmt,
6155            safe=safe,
6156            action=self._parse_var_from_options(self.CAST_ACTIONS, raise_unmatched=False),
6157        )
6158
6159    def _parse_string_agg(self) -> exp.GroupConcat:
6160        if self._match(TokenType.DISTINCT):
6161            args: t.List[t.Optional[exp.Expression]] = [
6162                self.expression(exp.Distinct, expressions=[self._parse_assignment()])
6163            ]
6164            if self._match(TokenType.COMMA):
6165                args.extend(self._parse_csv(self._parse_assignment))
6166        else:
6167            args = self._parse_csv(self._parse_assignment)  # type: ignore
6168
6169        if self._match_text_seq("ON", "OVERFLOW"):
6170            # trino: LISTAGG(expression [, separator] [ON OVERFLOW overflow_behavior])
6171            if self._match_text_seq("ERROR"):
6172                on_overflow: t.Optional[exp.Expression] = exp.var("ERROR")
6173            else:
6174                self._match_text_seq("TRUNCATE")
6175                on_overflow = self.expression(
6176                    exp.OverflowTruncateBehavior,
6177                    this=self._parse_string(),
6178                    with_count=(
6179                        self._match_text_seq("WITH", "COUNT")
6180                        or not self._match_text_seq("WITHOUT", "COUNT")
6181                    ),
6182                )
6183        else:
6184            on_overflow = None
6185
6186        index = self._index
6187        if not self._match(TokenType.R_PAREN) and args:
6188            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
6189            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
6190            args[-1] = self._parse_limit(this=self._parse_order(this=args[-1]))
6191            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
6192
6193        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
6194        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
6195        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
6196        if not self._match_text_seq("WITHIN", "GROUP"):
6197            self._retreat(index)
6198            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
6199
6200        # The corresponding match_r_paren will be called in parse_function (caller)
6201        self._match_l_paren()
6202
6203        return self.expression(
6204            exp.GroupConcat,
6205            this=self._parse_order(this=seq_get(args, 0)),
6206            separator=seq_get(args, 1),
6207            on_overflow=on_overflow,
6208        )
6209
6210    def _parse_convert(
6211        self, strict: bool, safe: t.Optional[bool] = None
6212    ) -> t.Optional[exp.Expression]:
6213        this = self._parse_bitwise()
6214
6215        if self._match(TokenType.USING):
6216            to: t.Optional[exp.Expression] = self.expression(
6217                exp.CharacterSet, this=self._parse_var()
6218            )
6219        elif self._match(TokenType.COMMA):
6220            to = self._parse_types()
6221        else:
6222            to = None
6223
6224        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
6225
6226    def _parse_xml_table(self) -> exp.XMLTable:
6227        namespaces = None
6228        passing = None
6229        columns = None
6230
6231        if self._match_text_seq("XMLNAMESPACES", "("):
6232            namespaces = self._parse_xml_namespace()
6233            self._match_text_seq(")", ",")
6234
6235        this = self._parse_string()
6236
6237        if self._match_text_seq("PASSING"):
6238            # The BY VALUE keywords are optional and are provided for semantic clarity
6239            self._match_text_seq("BY", "VALUE")
6240            passing = self._parse_csv(self._parse_column)
6241
6242        by_ref = self._match_text_seq("RETURNING", "SEQUENCE", "BY", "REF")
6243
6244        if self._match_text_seq("COLUMNS"):
6245            columns = self._parse_csv(self._parse_field_def)
6246
6247        return self.expression(
6248            exp.XMLTable,
6249            this=this,
6250            namespaces=namespaces,
6251            passing=passing,
6252            columns=columns,
6253            by_ref=by_ref,
6254        )
6255
6256    def _parse_xml_namespace(self) -> t.List[exp.XMLNamespace]:
6257        namespaces = []
6258
6259        while True:
6260            if self._match_text_seq("DEFAULT"):
6261                uri = self._parse_string()
6262            else:
6263                uri = self._parse_alias(self._parse_string())
6264            namespaces.append(self.expression(exp.XMLNamespace, this=uri))
6265            if not self._match(TokenType.COMMA):
6266                break
6267
6268        return namespaces
6269
6270    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
6271        """
6272        There are generally two variants of the DECODE function:
6273
6274        - DECODE(bin, charset)
6275        - DECODE(expression, search, result [, search, result] ... [, default])
6276
6277        The second variant will always be parsed into a CASE expression. Note that NULL
6278        needs special treatment, since we need to explicitly check for it with `IS NULL`,
6279        instead of relying on pattern matching.
6280        """
6281        args = self._parse_csv(self._parse_assignment)
6282
6283        if len(args) < 3:
6284            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
6285
6286        expression, *expressions = args
6287        if not expression:
6288            return None
6289
6290        ifs = []
6291        for search, result in zip(expressions[::2], expressions[1::2]):
6292            if not search or not result:
6293                return None
6294
6295            if isinstance(search, exp.Literal):
6296                ifs.append(
6297                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
6298                )
6299            elif isinstance(search, exp.Null):
6300                ifs.append(
6301                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
6302                )
6303            else:
6304                cond = exp.or_(
6305                    exp.EQ(this=expression.copy(), expression=search),
6306                    exp.and_(
6307                        exp.Is(this=expression.copy(), expression=exp.Null()),
6308                        exp.Is(this=search.copy(), expression=exp.Null()),
6309                        copy=False,
6310                    ),
6311                    copy=False,
6312                )
6313                ifs.append(exp.If(this=cond, true=result))
6314
6315        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
6316
6317    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
6318        self._match_text_seq("KEY")
6319        key = self._parse_column()
6320        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
6321        self._match_text_seq("VALUE")
6322        value = self._parse_bitwise()
6323
6324        if not key and not value:
6325            return None
6326        return self.expression(exp.JSONKeyValue, this=key, expression=value)
6327
6328    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
6329        if not this or not self._match_text_seq("FORMAT", "JSON"):
6330            return this
6331
6332        return self.expression(exp.FormatJson, this=this)
6333
6334    def _parse_on_condition(self) -> t.Optional[exp.OnCondition]:
6335        # MySQL uses "X ON EMPTY Y ON ERROR" (e.g. JSON_VALUE) while Oracle uses the opposite (e.g. JSON_EXISTS)
6336        if self.dialect.ON_CONDITION_EMPTY_BEFORE_ERROR:
6337            empty = self._parse_on_handling("EMPTY", *self.ON_CONDITION_TOKENS)
6338            error = self._parse_on_handling("ERROR", *self.ON_CONDITION_TOKENS)
6339        else:
6340            error = self._parse_on_handling("ERROR", *self.ON_CONDITION_TOKENS)
6341            empty = self._parse_on_handling("EMPTY", *self.ON_CONDITION_TOKENS)
6342
6343        null = self._parse_on_handling("NULL", *self.ON_CONDITION_TOKENS)
6344
6345        if not empty and not error and not null:
6346            return None
6347
6348        return self.expression(
6349            exp.OnCondition,
6350            empty=empty,
6351            error=error,
6352            null=null,
6353        )
6354
6355    def _parse_on_handling(
6356        self, on: str, *values: str
6357    ) -> t.Optional[str] | t.Optional[exp.Expression]:
6358        # Parses the "X ON Y" or "DEFAULT <expr> ON Y syntax, e.g. NULL ON NULL (Oracle, T-SQL, MySQL)
6359        for value in values:
6360            if self._match_text_seq(value, "ON", on):
6361                return f"{value} ON {on}"
6362
6363        index = self._index
6364        if self._match(TokenType.DEFAULT):
6365            default_value = self._parse_bitwise()
6366            if self._match_text_seq("ON", on):
6367                return default_value
6368
6369            self._retreat(index)
6370
6371        return None
6372
6373    @t.overload
6374    def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
6375
6376    @t.overload
6377    def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
6378
6379    def _parse_json_object(self, agg=False):
6380        star = self._parse_star()
6381        expressions = (
6382            [star]
6383            if star
6384            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
6385        )
6386        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
6387
6388        unique_keys = None
6389        if self._match_text_seq("WITH", "UNIQUE"):
6390            unique_keys = True
6391        elif self._match_text_seq("WITHOUT", "UNIQUE"):
6392            unique_keys = False
6393
6394        self._match_text_seq("KEYS")
6395
6396        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
6397            self._parse_type()
6398        )
6399        encoding = self._match_text_seq("ENCODING") and self._parse_var()
6400
6401        return self.expression(
6402            exp.JSONObjectAgg if agg else exp.JSONObject,
6403            expressions=expressions,
6404            null_handling=null_handling,
6405            unique_keys=unique_keys,
6406            return_type=return_type,
6407            encoding=encoding,
6408        )
6409
6410    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
6411    def _parse_json_column_def(self) -> exp.JSONColumnDef:
6412        if not self._match_text_seq("NESTED"):
6413            this = self._parse_id_var()
6414            kind = self._parse_types(allow_identifiers=False)
6415            nested = None
6416        else:
6417            this = None
6418            kind = None
6419            nested = True
6420
6421        path = self._match_text_seq("PATH") and self._parse_string()
6422        nested_schema = nested and self._parse_json_schema()
6423
6424        return self.expression(
6425            exp.JSONColumnDef,
6426            this=this,
6427            kind=kind,
6428            path=path,
6429            nested_schema=nested_schema,
6430        )
6431
6432    def _parse_json_schema(self) -> exp.JSONSchema:
6433        self._match_text_seq("COLUMNS")
6434        return self.expression(
6435            exp.JSONSchema,
6436            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
6437        )
6438
6439    def _parse_json_table(self) -> exp.JSONTable:
6440        this = self._parse_format_json(self._parse_bitwise())
6441        path = self._match(TokenType.COMMA) and self._parse_string()
6442        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
6443        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
6444        schema = self._parse_json_schema()
6445
6446        return exp.JSONTable(
6447            this=this,
6448            schema=schema,
6449            path=path,
6450            error_handling=error_handling,
6451            empty_handling=empty_handling,
6452        )
6453
6454    def _parse_match_against(self) -> exp.MatchAgainst:
6455        expressions = self._parse_csv(self._parse_column)
6456
6457        self._match_text_seq(")", "AGAINST", "(")
6458
6459        this = self._parse_string()
6460
6461        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
6462            modifier = "IN NATURAL LANGUAGE MODE"
6463            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
6464                modifier = f"{modifier} WITH QUERY EXPANSION"
6465        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
6466            modifier = "IN BOOLEAN MODE"
6467        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
6468            modifier = "WITH QUERY EXPANSION"
6469        else:
6470            modifier = None
6471
6472        return self.expression(
6473            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
6474        )
6475
6476    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
6477    def _parse_open_json(self) -> exp.OpenJSON:
6478        this = self._parse_bitwise()
6479        path = self._match(TokenType.COMMA) and self._parse_string()
6480
6481        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
6482            this = self._parse_field(any_token=True)
6483            kind = self._parse_types()
6484            path = self._parse_string()
6485            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
6486
6487            return self.expression(
6488                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
6489            )
6490
6491        expressions = None
6492        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
6493            self._match_l_paren()
6494            expressions = self._parse_csv(_parse_open_json_column_def)
6495
6496        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
6497
6498    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
6499        args = self._parse_csv(self._parse_bitwise)
6500
6501        if self._match(TokenType.IN):
6502            return self.expression(
6503                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
6504            )
6505
6506        if haystack_first:
6507            haystack = seq_get(args, 0)
6508            needle = seq_get(args, 1)
6509        else:
6510            haystack = seq_get(args, 1)
6511            needle = seq_get(args, 0)
6512
6513        return self.expression(
6514            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
6515        )
6516
6517    def _parse_predict(self) -> exp.Predict:
6518        self._match_text_seq("MODEL")
6519        this = self._parse_table()
6520
6521        self._match(TokenType.COMMA)
6522        self._match_text_seq("TABLE")
6523
6524        return self.expression(
6525            exp.Predict,
6526            this=this,
6527            expression=self._parse_table(),
6528            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
6529        )
6530
6531    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
6532        args = self._parse_csv(self._parse_table)
6533        return exp.JoinHint(this=func_name.upper(), expressions=args)
6534
6535    def _parse_substring(self) -> exp.Substring:
6536        # Postgres supports the form: substring(string [from int] [for int])
6537        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
6538
6539        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
6540
6541        if self._match(TokenType.FROM):
6542            args.append(self._parse_bitwise())
6543        if self._match(TokenType.FOR):
6544            if len(args) == 1:
6545                args.append(exp.Literal.number(1))
6546            args.append(self._parse_bitwise())
6547
6548        return self.validate_expression(exp.Substring.from_arg_list(args), args)
6549
6550    def _parse_trim(self) -> exp.Trim:
6551        # https://www.w3resource.com/sql/character-functions/trim.php
6552        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
6553
6554        position = None
6555        collation = None
6556        expression = None
6557
6558        if self._match_texts(self.TRIM_TYPES):
6559            position = self._prev.text.upper()
6560
6561        this = self._parse_bitwise()
6562        if self._match_set((TokenType.FROM, TokenType.COMMA)):
6563            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
6564            expression = self._parse_bitwise()
6565
6566            if invert_order:
6567                this, expression = expression, this
6568
6569        if self._match(TokenType.COLLATE):
6570            collation = self._parse_bitwise()
6571
6572        return self.expression(
6573            exp.Trim, this=this, position=position, expression=expression, collation=collation
6574        )
6575
6576    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
6577        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
6578
6579    def _parse_named_window(self) -> t.Optional[exp.Expression]:
6580        return self._parse_window(self._parse_id_var(), alias=True)
6581
6582    def _parse_respect_or_ignore_nulls(
6583        self, this: t.Optional[exp.Expression]
6584    ) -> t.Optional[exp.Expression]:
6585        if self._match_text_seq("IGNORE", "NULLS"):
6586            return self.expression(exp.IgnoreNulls, this=this)
6587        if self._match_text_seq("RESPECT", "NULLS"):
6588            return self.expression(exp.RespectNulls, this=this)
6589        return this
6590
6591    def _parse_having_max(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
6592        if self._match(TokenType.HAVING):
6593            self._match_texts(("MAX", "MIN"))
6594            max = self._prev.text.upper() != "MIN"
6595            return self.expression(
6596                exp.HavingMax, this=this, expression=self._parse_column(), max=max
6597            )
6598
6599        return this
6600
6601    def _parse_window(
6602        self, this: t.Optional[exp.Expression], alias: bool = False
6603    ) -> t.Optional[exp.Expression]:
6604        func = this
6605        comments = func.comments if isinstance(func, exp.Expression) else None
6606
6607        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
6608        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
6609        if self._match_text_seq("WITHIN", "GROUP"):
6610            order = self._parse_wrapped(self._parse_order)
6611            this = self.expression(exp.WithinGroup, this=this, expression=order)
6612
6613        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
6614            self._match(TokenType.WHERE)
6615            this = self.expression(
6616                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
6617            )
6618            self._match_r_paren()
6619
6620        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
6621        # Some dialects choose to implement and some do not.
6622        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
6623
6624        # There is some code above in _parse_lambda that handles
6625        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
6626
6627        # The below changes handle
6628        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
6629
6630        # Oracle allows both formats
6631        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
6632        #   and Snowflake chose to do the same for familiarity
6633        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
6634        if isinstance(this, exp.AggFunc):
6635            ignore_respect = this.find(exp.IgnoreNulls, exp.RespectNulls)
6636
6637            if ignore_respect and ignore_respect is not this:
6638                ignore_respect.replace(ignore_respect.this)
6639                this = self.expression(ignore_respect.__class__, this=this)
6640
6641        this = self._parse_respect_or_ignore_nulls(this)
6642
6643        # bigquery select from window x AS (partition by ...)
6644        if alias:
6645            over = None
6646            self._match(TokenType.ALIAS)
6647        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
6648            return this
6649        else:
6650            over = self._prev.text.upper()
6651
6652        if comments and isinstance(func, exp.Expression):
6653            func.pop_comments()
6654
6655        if not self._match(TokenType.L_PAREN):
6656            return self.expression(
6657                exp.Window,
6658                comments=comments,
6659                this=this,
6660                alias=self._parse_id_var(False),
6661                over=over,
6662            )
6663
6664        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
6665
6666        first = self._match(TokenType.FIRST)
6667        if self._match_text_seq("LAST"):
6668            first = False
6669
6670        partition, order = self._parse_partition_and_order()
6671        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
6672
6673        if kind:
6674            self._match(TokenType.BETWEEN)
6675            start = self._parse_window_spec()
6676            self._match(TokenType.AND)
6677            end = self._parse_window_spec()
6678
6679            spec = self.expression(
6680                exp.WindowSpec,
6681                kind=kind,
6682                start=start["value"],
6683                start_side=start["side"],
6684                end=end["value"],
6685                end_side=end["side"],
6686            )
6687        else:
6688            spec = None
6689
6690        self._match_r_paren()
6691
6692        window = self.expression(
6693            exp.Window,
6694            comments=comments,
6695            this=this,
6696            partition_by=partition,
6697            order=order,
6698            spec=spec,
6699            alias=window_alias,
6700            over=over,
6701            first=first,
6702        )
6703
6704        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
6705        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
6706            return self._parse_window(window, alias=alias)
6707
6708        return window
6709
6710    def _parse_partition_and_order(
6711        self,
6712    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
6713        return self._parse_partition_by(), self._parse_order()
6714
6715    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
6716        self._match(TokenType.BETWEEN)
6717
6718        return {
6719            "value": (
6720                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
6721                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
6722                or self._parse_bitwise()
6723            ),
6724            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
6725        }
6726
6727    def _parse_alias(
6728        self, this: t.Optional[exp.Expression], explicit: bool = False
6729    ) -> t.Optional[exp.Expression]:
6730        # In some dialects, LIMIT and OFFSET can act as both identifiers and keywords (clauses)
6731        # so this section tries to parse the clause version and if it fails, it treats the token
6732        # as an identifier (alias)
6733        if self._can_parse_limit_or_offset():
6734            return this
6735
6736        any_token = self._match(TokenType.ALIAS)
6737        comments = self._prev_comments or []
6738
6739        if explicit and not any_token:
6740            return this
6741
6742        if self._match(TokenType.L_PAREN):
6743            aliases = self.expression(
6744                exp.Aliases,
6745                comments=comments,
6746                this=this,
6747                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
6748            )
6749            self._match_r_paren(aliases)
6750            return aliases
6751
6752        alias = self._parse_id_var(any_token, tokens=self.ALIAS_TOKENS) or (
6753            self.STRING_ALIASES and self._parse_string_as_identifier()
6754        )
6755
6756        if alias:
6757            comments.extend(alias.pop_comments())
6758            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
6759            column = this.this
6760
6761            # Moves the comment next to the alias in `expr /* comment */ AS alias`
6762            if not this.comments and column and column.comments:
6763                this.comments = column.pop_comments()
6764
6765        return this
6766
6767    def _parse_id_var(
6768        self,
6769        any_token: bool = True,
6770        tokens: t.Optional[t.Collection[TokenType]] = None,
6771    ) -> t.Optional[exp.Expression]:
6772        expression = self._parse_identifier()
6773        if not expression and (
6774            (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS)
6775        ):
6776            quoted = self._prev.token_type == TokenType.STRING
6777            expression = self.expression(exp.Identifier, this=self._prev.text, quoted=quoted)
6778
6779        return expression
6780
6781    def _parse_string(self) -> t.Optional[exp.Expression]:
6782        if self._match_set(self.STRING_PARSERS):
6783            return self.STRING_PARSERS[self._prev.token_type](self, self._prev)
6784        return self._parse_placeholder()
6785
6786    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
6787        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
6788
6789    def _parse_number(self) -> t.Optional[exp.Expression]:
6790        if self._match_set(self.NUMERIC_PARSERS):
6791            return self.NUMERIC_PARSERS[self._prev.token_type](self, self._prev)
6792        return self._parse_placeholder()
6793
6794    def _parse_identifier(self) -> t.Optional[exp.Expression]:
6795        if self._match(TokenType.IDENTIFIER):
6796            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
6797        return self._parse_placeholder()
6798
6799    def _parse_var(
6800        self,
6801        any_token: bool = False,
6802        tokens: t.Optional[t.Collection[TokenType]] = None,
6803        upper: bool = False,
6804    ) -> t.Optional[exp.Expression]:
6805        if (
6806            (any_token and self._advance_any())
6807            or self._match(TokenType.VAR)
6808            or (self._match_set(tokens) if tokens else False)
6809        ):
6810            return self.expression(
6811                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
6812            )
6813        return self._parse_placeholder()
6814
6815    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
6816        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
6817            self._advance()
6818            return self._prev
6819        return None
6820
6821    def _parse_var_or_string(self, upper: bool = False) -> t.Optional[exp.Expression]:
6822        return self._parse_string() or self._parse_var(any_token=True, upper=upper)
6823
6824    def _parse_primary_or_var(self) -> t.Optional[exp.Expression]:
6825        return self._parse_primary() or self._parse_var(any_token=True)
6826
6827    def _parse_null(self) -> t.Optional[exp.Expression]:
6828        if self._match_set(self.NULL_TOKENS):
6829            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
6830        return self._parse_placeholder()
6831
6832    def _parse_boolean(self) -> t.Optional[exp.Expression]:
6833        if self._match(TokenType.TRUE):
6834            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
6835        if self._match(TokenType.FALSE):
6836            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
6837        return self._parse_placeholder()
6838
6839    def _parse_star(self) -> t.Optional[exp.Expression]:
6840        if self._match(TokenType.STAR):
6841            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
6842        return self._parse_placeholder()
6843
6844    def _parse_parameter(self) -> exp.Parameter:
6845        this = self._parse_identifier() or self._parse_primary_or_var()
6846        return self.expression(exp.Parameter, this=this)
6847
6848    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
6849        if self._match_set(self.PLACEHOLDER_PARSERS):
6850            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
6851            if placeholder:
6852                return placeholder
6853            self._advance(-1)
6854        return None
6855
6856    def _parse_star_op(self, *keywords: str) -> t.Optional[t.List[exp.Expression]]:
6857        if not self._match_texts(keywords):
6858            return None
6859        if self._match(TokenType.L_PAREN, advance=False):
6860            return self._parse_wrapped_csv(self._parse_expression)
6861
6862        expression = self._parse_expression()
6863        return [expression] if expression else None
6864
6865    def _parse_csv(
6866        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
6867    ) -> t.List[exp.Expression]:
6868        parse_result = parse_method()
6869        items = [parse_result] if parse_result is not None else []
6870
6871        while self._match(sep):
6872            self._add_comments(parse_result)
6873            parse_result = parse_method()
6874            if parse_result is not None:
6875                items.append(parse_result)
6876
6877        return items
6878
6879    def _parse_tokens(
6880        self, parse_method: t.Callable, expressions: t.Dict
6881    ) -> t.Optional[exp.Expression]:
6882        this = parse_method()
6883
6884        while self._match_set(expressions):
6885            this = self.expression(
6886                expressions[self._prev.token_type],
6887                this=this,
6888                comments=self._prev_comments,
6889                expression=parse_method(),
6890            )
6891
6892        return this
6893
6894    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
6895        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
6896
6897    def _parse_wrapped_csv(
6898        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
6899    ) -> t.List[exp.Expression]:
6900        return self._parse_wrapped(
6901            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
6902        )
6903
6904    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
6905        wrapped = self._match(TokenType.L_PAREN)
6906        if not wrapped and not optional:
6907            self.raise_error("Expecting (")
6908        parse_result = parse_method()
6909        if wrapped:
6910            self._match_r_paren()
6911        return parse_result
6912
6913    def _parse_expressions(self) -> t.List[exp.Expression]:
6914        return self._parse_csv(self._parse_expression)
6915
6916    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
6917        return self._parse_select() or self._parse_set_operations(
6918            self._parse_alias(self._parse_assignment(), explicit=True)
6919            if alias
6920            else self._parse_assignment()
6921        )
6922
6923    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
6924        return self._parse_query_modifiers(
6925            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
6926        )
6927
6928    def _parse_transaction(self) -> exp.Transaction | exp.Command:
6929        this = None
6930        if self._match_texts(self.TRANSACTION_KIND):
6931            this = self._prev.text
6932
6933        self._match_texts(("TRANSACTION", "WORK"))
6934
6935        modes = []
6936        while True:
6937            mode = []
6938            while self._match(TokenType.VAR):
6939                mode.append(self._prev.text)
6940
6941            if mode:
6942                modes.append(" ".join(mode))
6943            if not self._match(TokenType.COMMA):
6944                break
6945
6946        return self.expression(exp.Transaction, this=this, modes=modes)
6947
6948    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
6949        chain = None
6950        savepoint = None
6951        is_rollback = self._prev.token_type == TokenType.ROLLBACK
6952
6953        self._match_texts(("TRANSACTION", "WORK"))
6954
6955        if self._match_text_seq("TO"):
6956            self._match_text_seq("SAVEPOINT")
6957            savepoint = self._parse_id_var()
6958
6959        if self._match(TokenType.AND):
6960            chain = not self._match_text_seq("NO")
6961            self._match_text_seq("CHAIN")
6962
6963        if is_rollback:
6964            return self.expression(exp.Rollback, savepoint=savepoint)
6965
6966        return self.expression(exp.Commit, chain=chain)
6967
6968    def _parse_refresh(self) -> exp.Refresh:
6969        self._match(TokenType.TABLE)
6970        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
6971
6972    def _parse_add_column(self) -> t.Optional[exp.Expression]:
6973        if not self._match_text_seq("ADD"):
6974            return None
6975
6976        self._match(TokenType.COLUMN)
6977        exists_column = self._parse_exists(not_=True)
6978        expression = self._parse_field_def()
6979
6980        if expression:
6981            expression.set("exists", exists_column)
6982
6983            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
6984            if self._match_texts(("FIRST", "AFTER")):
6985                position = self._prev.text
6986                column_position = self.expression(
6987                    exp.ColumnPosition, this=self._parse_column(), position=position
6988                )
6989                expression.set("position", column_position)
6990
6991        return expression
6992
6993    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
6994        drop = self._match(TokenType.DROP) and self._parse_drop()
6995        if drop and not isinstance(drop, exp.Command):
6996            drop.set("kind", drop.args.get("kind", "COLUMN"))
6997        return drop
6998
6999    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
7000    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
7001        return self.expression(
7002            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
7003        )
7004
7005    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
7006        index = self._index - 1
7007
7008        if self._match_set(self.ADD_CONSTRAINT_TOKENS, advance=False):
7009            return self._parse_csv(
7010                lambda: self.expression(
7011                    exp.AddConstraint, expressions=self._parse_csv(self._parse_constraint)
7012                )
7013            )
7014
7015        self._retreat(index)
7016        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
7017            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
7018
7019        if self._match_text_seq("ADD", "COLUMNS"):
7020            schema = self._parse_schema()
7021            if schema:
7022                return [schema]
7023            return []
7024
7025        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
7026
7027    def _parse_alter_table_alter(self) -> t.Optional[exp.Expression]:
7028        if self._match_texts(self.ALTER_ALTER_PARSERS):
7029            return self.ALTER_ALTER_PARSERS[self._prev.text.upper()](self)
7030
7031        # Many dialects support the ALTER [COLUMN] syntax, so if there is no
7032        # keyword after ALTER we default to parsing this statement
7033        self._match(TokenType.COLUMN)
7034        column = self._parse_field(any_token=True)
7035
7036        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
7037            return self.expression(exp.AlterColumn, this=column, drop=True)
7038        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
7039            return self.expression(exp.AlterColumn, this=column, default=self._parse_assignment())
7040        if self._match(TokenType.COMMENT):
7041            return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
7042        if self._match_text_seq("DROP", "NOT", "NULL"):
7043            return self.expression(
7044                exp.AlterColumn,
7045                this=column,
7046                drop=True,
7047                allow_null=True,
7048            )
7049        if self._match_text_seq("SET", "NOT", "NULL"):
7050            return self.expression(
7051                exp.AlterColumn,
7052                this=column,
7053                allow_null=False,
7054            )
7055        self._match_text_seq("SET", "DATA")
7056        self._match_text_seq("TYPE")
7057        return self.expression(
7058            exp.AlterColumn,
7059            this=column,
7060            dtype=self._parse_types(),
7061            collate=self._match(TokenType.COLLATE) and self._parse_term(),
7062            using=self._match(TokenType.USING) and self._parse_assignment(),
7063        )
7064
7065    def _parse_alter_diststyle(self) -> exp.AlterDistStyle:
7066        if self._match_texts(("ALL", "EVEN", "AUTO")):
7067            return self.expression(exp.AlterDistStyle, this=exp.var(self._prev.text.upper()))
7068
7069        self._match_text_seq("KEY", "DISTKEY")
7070        return self.expression(exp.AlterDistStyle, this=self._parse_column())
7071
7072    def _parse_alter_sortkey(self, compound: t.Optional[bool] = None) -> exp.AlterSortKey:
7073        if compound:
7074            self._match_text_seq("SORTKEY")
7075
7076        if self._match(TokenType.L_PAREN, advance=False):
7077            return self.expression(
7078                exp.AlterSortKey, expressions=self._parse_wrapped_id_vars(), compound=compound
7079            )
7080
7081        self._match_texts(("AUTO", "NONE"))
7082        return self.expression(
7083            exp.AlterSortKey, this=exp.var(self._prev.text.upper()), compound=compound
7084        )
7085
7086    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
7087        index = self._index - 1
7088
7089        partition_exists = self._parse_exists()
7090        if self._match(TokenType.PARTITION, advance=False):
7091            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
7092
7093        self._retreat(index)
7094        return self._parse_csv(self._parse_drop_column)
7095
7096    def _parse_alter_table_rename(self) -> t.Optional[exp.AlterRename | exp.RenameColumn]:
7097        if self._match(TokenType.COLUMN):
7098            exists = self._parse_exists()
7099            old_column = self._parse_column()
7100            to = self._match_text_seq("TO")
7101            new_column = self._parse_column()
7102
7103            if old_column is None or to is None or new_column is None:
7104                return None
7105
7106            return self.expression(exp.RenameColumn, this=old_column, to=new_column, exists=exists)
7107
7108        self._match_text_seq("TO")
7109        return self.expression(exp.AlterRename, this=self._parse_table(schema=True))
7110
7111    def _parse_alter_table_set(self) -> exp.AlterSet:
7112        alter_set = self.expression(exp.AlterSet)
7113
7114        if self._match(TokenType.L_PAREN, advance=False) or self._match_text_seq(
7115            "TABLE", "PROPERTIES"
7116        ):
7117            alter_set.set("expressions", self._parse_wrapped_csv(self._parse_assignment))
7118        elif self._match_text_seq("FILESTREAM_ON", advance=False):
7119            alter_set.set("expressions", [self._parse_assignment()])
7120        elif self._match_texts(("LOGGED", "UNLOGGED")):
7121            alter_set.set("option", exp.var(self._prev.text.upper()))
7122        elif self._match_text_seq("WITHOUT") and self._match_texts(("CLUSTER", "OIDS")):
7123            alter_set.set("option", exp.var(f"WITHOUT {self._prev.text.upper()}"))
7124        elif self._match_text_seq("LOCATION"):
7125            alter_set.set("location", self._parse_field())
7126        elif self._match_text_seq("ACCESS", "METHOD"):
7127            alter_set.set("access_method", self._parse_field())
7128        elif self._match_text_seq("TABLESPACE"):
7129            alter_set.set("tablespace", self._parse_field())
7130        elif self._match_text_seq("FILE", "FORMAT") or self._match_text_seq("FILEFORMAT"):
7131            alter_set.set("file_format", [self._parse_field()])
7132        elif self._match_text_seq("STAGE_FILE_FORMAT"):
7133            alter_set.set("file_format", self._parse_wrapped_options())
7134        elif self._match_text_seq("STAGE_COPY_OPTIONS"):
7135            alter_set.set("copy_options", self._parse_wrapped_options())
7136        elif self._match_text_seq("TAG") or self._match_text_seq("TAGS"):
7137            alter_set.set("tag", self._parse_csv(self._parse_assignment))
7138        else:
7139            if self._match_text_seq("SERDE"):
7140                alter_set.set("serde", self._parse_field())
7141
7142            alter_set.set("expressions", [self._parse_properties()])
7143
7144        return alter_set
7145
7146    def _parse_alter(self) -> exp.Alter | exp.Command:
7147        start = self._prev
7148
7149        alter_token = self._match_set(self.ALTERABLES) and self._prev
7150        if not alter_token:
7151            return self._parse_as_command(start)
7152
7153        exists = self._parse_exists()
7154        only = self._match_text_seq("ONLY")
7155        this = self._parse_table(schema=True)
7156        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
7157
7158        if self._next:
7159            self._advance()
7160
7161        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
7162        if parser:
7163            actions = ensure_list(parser(self))
7164            not_valid = self._match_text_seq("NOT", "VALID")
7165            options = self._parse_csv(self._parse_property)
7166
7167            if not self._curr and actions:
7168                return self.expression(
7169                    exp.Alter,
7170                    this=this,
7171                    kind=alter_token.text.upper(),
7172                    exists=exists,
7173                    actions=actions,
7174                    only=only,
7175                    options=options,
7176                    cluster=cluster,
7177                    not_valid=not_valid,
7178                )
7179
7180        return self._parse_as_command(start)
7181
7182    def _parse_analyze(self) -> exp.Analyze | exp.Command:
7183        start = self._prev
7184        # https://duckdb.org/docs/sql/statements/analyze
7185        if not self._curr:
7186            return self.expression(exp.Analyze)
7187
7188        options = []
7189        while self._match_texts(self.ANALYZE_STYLES):
7190            if self._prev.text.upper() == "BUFFER_USAGE_LIMIT":
7191                options.append(f"BUFFER_USAGE_LIMIT {self._parse_number()}")
7192            else:
7193                options.append(self._prev.text.upper())
7194
7195        this: t.Optional[exp.Expression] = None
7196        inner_expression: t.Optional[exp.Expression] = None
7197
7198        kind = self._curr and self._curr.text.upper()
7199
7200        if self._match(TokenType.TABLE) or self._match(TokenType.INDEX):
7201            this = self._parse_table_parts()
7202        elif self._match_text_seq("TABLES"):
7203            if self._match_set((TokenType.FROM, TokenType.IN)):
7204                kind = f"{kind} {self._prev.text.upper()}"
7205                this = self._parse_table(schema=True, is_db_reference=True)
7206        elif self._match_text_seq("DATABASE"):
7207            this = self._parse_table(schema=True, is_db_reference=True)
7208        elif self._match_text_seq("CLUSTER"):
7209            this = self._parse_table()
7210        # Try matching inner expr keywords before fallback to parse table.
7211        elif self._match_texts(self.ANALYZE_EXPRESSION_PARSERS):
7212            kind = None
7213            inner_expression = self.ANALYZE_EXPRESSION_PARSERS[self._prev.text.upper()](self)
7214        else:
7215            # Empty kind  https://prestodb.io/docs/current/sql/analyze.html
7216            kind = None
7217            this = self._parse_table_parts()
7218
7219        partition = self._try_parse(self._parse_partition)
7220        if not partition and self._match_texts(self.PARTITION_KEYWORDS):
7221            return self._parse_as_command(start)
7222
7223        # https://docs.starrocks.io/docs/sql-reference/sql-statements/cbo_stats/ANALYZE_TABLE/
7224        if self._match_text_seq("WITH", "SYNC", "MODE") or self._match_text_seq(
7225            "WITH", "ASYNC", "MODE"
7226        ):
7227            mode = f"WITH {self._tokens[self._index-2].text.upper()} MODE"
7228        else:
7229            mode = None
7230
7231        if self._match_texts(self.ANALYZE_EXPRESSION_PARSERS):
7232            inner_expression = self.ANALYZE_EXPRESSION_PARSERS[self._prev.text.upper()](self)
7233
7234        properties = self._parse_properties()
7235        return self.expression(
7236            exp.Analyze,
7237            kind=kind,
7238            this=this,
7239            mode=mode,
7240            partition=partition,
7241            properties=properties,
7242            expression=inner_expression,
7243            options=options,
7244        )
7245
7246    # https://spark.apache.org/docs/3.5.1/sql-ref-syntax-aux-analyze-table.html
7247    def _parse_analyze_statistics(self) -> exp.AnalyzeStatistics:
7248        this = None
7249        kind = self._prev.text.upper()
7250        option = self._prev.text.upper() if self._match_text_seq("DELTA") else None
7251        expressions = []
7252
7253        if not self._match_text_seq("STATISTICS"):
7254            self.raise_error("Expecting token STATISTICS")
7255
7256        if self._match_text_seq("NOSCAN"):
7257            this = "NOSCAN"
7258        elif self._match(TokenType.FOR):
7259            if self._match_text_seq("ALL", "COLUMNS"):
7260                this = "FOR ALL COLUMNS"
7261            if self._match_texts("COLUMNS"):
7262                this = "FOR COLUMNS"
7263                expressions = self._parse_csv(self._parse_column_reference)
7264        elif self._match_text_seq("SAMPLE"):
7265            sample = self._parse_number()
7266            expressions = [
7267                self.expression(
7268                    exp.AnalyzeSample,
7269                    sample=sample,
7270                    kind=self._prev.text.upper() if self._match(TokenType.PERCENT) else None,
7271                )
7272            ]
7273
7274        return self.expression(
7275            exp.AnalyzeStatistics, kind=kind, option=option, this=this, expressions=expressions
7276        )
7277
7278    # https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/ANALYZE.html
7279    def _parse_analyze_validate(self) -> exp.AnalyzeValidate:
7280        kind = None
7281        this = None
7282        expression: t.Optional[exp.Expression] = None
7283        if self._match_text_seq("REF", "UPDATE"):
7284            kind = "REF"
7285            this = "UPDATE"
7286            if self._match_text_seq("SET", "DANGLING", "TO", "NULL"):
7287                this = "UPDATE SET DANGLING TO NULL"
7288        elif self._match_text_seq("STRUCTURE"):
7289            kind = "STRUCTURE"
7290            if self._match_text_seq("CASCADE", "FAST"):
7291                this = "CASCADE FAST"
7292            elif self._match_text_seq("CASCADE", "COMPLETE") and self._match_texts(
7293                ("ONLINE", "OFFLINE")
7294            ):
7295                this = f"CASCADE COMPLETE {self._prev.text.upper()}"
7296                expression = self._parse_into()
7297
7298        return self.expression(exp.AnalyzeValidate, kind=kind, this=this, expression=expression)
7299
7300    def _parse_analyze_columns(self) -> t.Optional[exp.AnalyzeColumns]:
7301        this = self._prev.text.upper()
7302        if self._match_text_seq("COLUMNS"):
7303            return self.expression(exp.AnalyzeColumns, this=f"{this} {self._prev.text.upper()}")
7304        return None
7305
7306    def _parse_analyze_delete(self) -> t.Optional[exp.AnalyzeDelete]:
7307        kind = self._prev.text.upper() if self._match_text_seq("SYSTEM") else None
7308        if self._match_text_seq("STATISTICS"):
7309            return self.expression(exp.AnalyzeDelete, kind=kind)
7310        return None
7311
7312    def _parse_analyze_list(self) -> t.Optional[exp.AnalyzeListChainedRows]:
7313        if self._match_text_seq("CHAINED", "ROWS"):
7314            return self.expression(exp.AnalyzeListChainedRows, expression=self._parse_into())
7315        return None
7316
7317    # https://dev.mysql.com/doc/refman/8.4/en/analyze-table.html
7318    def _parse_analyze_histogram(self) -> exp.AnalyzeHistogram:
7319        this = self._prev.text.upper()
7320        expression: t.Optional[exp.Expression] = None
7321        expressions = []
7322        update_options = None
7323
7324        if self._match_text_seq("HISTOGRAM", "ON"):
7325            expressions = self._parse_csv(self._parse_column_reference)
7326            with_expressions = []
7327            while self._match(TokenType.WITH):
7328                # https://docs.starrocks.io/docs/sql-reference/sql-statements/cbo_stats/ANALYZE_TABLE/
7329                if self._match_texts(("SYNC", "ASYNC")):
7330                    if self._match_text_seq("MODE", advance=False):
7331                        with_expressions.append(f"{self._prev.text.upper()} MODE")
7332                        self._advance()
7333                else:
7334                    buckets = self._parse_number()
7335                    if self._match_text_seq("BUCKETS"):
7336                        with_expressions.append(f"{buckets} BUCKETS")
7337            if with_expressions:
7338                expression = self.expression(exp.AnalyzeWith, expressions=with_expressions)
7339
7340            if self._match_texts(("MANUAL", "AUTO")) and self._match(
7341                TokenType.UPDATE, advance=False
7342            ):
7343                update_options = self._prev.text.upper()
7344                self._advance()
7345            elif self._match_text_seq("USING", "DATA"):
7346                expression = self.expression(exp.UsingData, this=self._parse_string())
7347
7348        return self.expression(
7349            exp.AnalyzeHistogram,
7350            this=this,
7351            expressions=expressions,
7352            expression=expression,
7353            update_options=update_options,
7354        )
7355
7356    def _parse_merge(self) -> exp.Merge:
7357        self._match(TokenType.INTO)
7358        target = self._parse_table()
7359
7360        if target and self._match(TokenType.ALIAS, advance=False):
7361            target.set("alias", self._parse_table_alias())
7362
7363        self._match(TokenType.USING)
7364        using = self._parse_table()
7365
7366        self._match(TokenType.ON)
7367        on = self._parse_assignment()
7368
7369        return self.expression(
7370            exp.Merge,
7371            this=target,
7372            using=using,
7373            on=on,
7374            whens=self._parse_when_matched(),
7375            returning=self._parse_returning(),
7376        )
7377
7378    def _parse_when_matched(self) -> exp.Whens:
7379        whens = []
7380
7381        while self._match(TokenType.WHEN):
7382            matched = not self._match(TokenType.NOT)
7383            self._match_text_seq("MATCHED")
7384            source = (
7385                False
7386                if self._match_text_seq("BY", "TARGET")
7387                else self._match_text_seq("BY", "SOURCE")
7388            )
7389            condition = self._parse_assignment() if self._match(TokenType.AND) else None
7390
7391            self._match(TokenType.THEN)
7392
7393            if self._match(TokenType.INSERT):
7394                this = self._parse_star()
7395                if this:
7396                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=this)
7397                else:
7398                    then = self.expression(
7399                        exp.Insert,
7400                        this=exp.var("ROW") if self._match_text_seq("ROW") else self._parse_value(),
7401                        expression=self._match_text_seq("VALUES") and self._parse_value(),
7402                    )
7403            elif self._match(TokenType.UPDATE):
7404                expressions = self._parse_star()
7405                if expressions:
7406                    then = self.expression(exp.Update, expressions=expressions)
7407                else:
7408                    then = self.expression(
7409                        exp.Update,
7410                        expressions=self._match(TokenType.SET)
7411                        and self._parse_csv(self._parse_equality),
7412                    )
7413            elif self._match(TokenType.DELETE):
7414                then = self.expression(exp.Var, this=self._prev.text)
7415            else:
7416                then = self._parse_var_from_options(self.CONFLICT_ACTIONS)
7417
7418            whens.append(
7419                self.expression(
7420                    exp.When,
7421                    matched=matched,
7422                    source=source,
7423                    condition=condition,
7424                    then=then,
7425                )
7426            )
7427        return self.expression(exp.Whens, expressions=whens)
7428
7429    def _parse_show(self) -> t.Optional[exp.Expression]:
7430        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
7431        if parser:
7432            return parser(self)
7433        return self._parse_as_command(self._prev)
7434
7435    def _parse_set_item_assignment(
7436        self, kind: t.Optional[str] = None
7437    ) -> t.Optional[exp.Expression]:
7438        index = self._index
7439
7440        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
7441            return self._parse_set_transaction(global_=kind == "GLOBAL")
7442
7443        left = self._parse_primary() or self._parse_column()
7444        assignment_delimiter = self._match_texts(("=", "TO"))
7445
7446        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
7447            self._retreat(index)
7448            return None
7449
7450        right = self._parse_statement() or self._parse_id_var()
7451        if isinstance(right, (exp.Column, exp.Identifier)):
7452            right = exp.var(right.name)
7453
7454        this = self.expression(exp.EQ, this=left, expression=right)
7455        return self.expression(exp.SetItem, this=this, kind=kind)
7456
7457    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
7458        self._match_text_seq("TRANSACTION")
7459        characteristics = self._parse_csv(
7460            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
7461        )
7462        return self.expression(
7463            exp.SetItem,
7464            expressions=characteristics,
7465            kind="TRANSACTION",
7466            **{"global": global_},  # type: ignore
7467        )
7468
7469    def _parse_set_item(self) -> t.Optional[exp.Expression]:
7470        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
7471        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
7472
7473    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
7474        index = self._index
7475        set_ = self.expression(
7476            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
7477        )
7478
7479        if self._curr:
7480            self._retreat(index)
7481            return self._parse_as_command(self._prev)
7482
7483        return set_
7484
7485    def _parse_var_from_options(
7486        self, options: OPTIONS_TYPE, raise_unmatched: bool = True
7487    ) -> t.Optional[exp.Var]:
7488        start = self._curr
7489        if not start:
7490            return None
7491
7492        option = start.text.upper()
7493        continuations = options.get(option)
7494
7495        index = self._index
7496        self._advance()
7497        for keywords in continuations or []:
7498            if isinstance(keywords, str):
7499                keywords = (keywords,)
7500
7501            if self._match_text_seq(*keywords):
7502                option = f"{option} {' '.join(keywords)}"
7503                break
7504        else:
7505            if continuations or continuations is None:
7506                if raise_unmatched:
7507                    self.raise_error(f"Unknown option {option}")
7508
7509                self._retreat(index)
7510                return None
7511
7512        return exp.var(option)
7513
7514    def _parse_as_command(self, start: Token) -> exp.Command:
7515        while self._curr:
7516            self._advance()
7517        text = self._find_sql(start, self._prev)
7518        size = len(start.text)
7519        self._warn_unsupported()
7520        return exp.Command(this=text[:size], expression=text[size:])
7521
7522    def _parse_dict_property(self, this: str) -> exp.DictProperty:
7523        settings = []
7524
7525        self._match_l_paren()
7526        kind = self._parse_id_var()
7527
7528        if self._match(TokenType.L_PAREN):
7529            while True:
7530                key = self._parse_id_var()
7531                value = self._parse_primary()
7532                if not key and value is None:
7533                    break
7534                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
7535            self._match(TokenType.R_PAREN)
7536
7537        self._match_r_paren()
7538
7539        return self.expression(
7540            exp.DictProperty,
7541            this=this,
7542            kind=kind.this if kind else None,
7543            settings=settings,
7544        )
7545
7546    def _parse_dict_range(self, this: str) -> exp.DictRange:
7547        self._match_l_paren()
7548        has_min = self._match_text_seq("MIN")
7549        if has_min:
7550            min = self._parse_var() or self._parse_primary()
7551            self._match_text_seq("MAX")
7552            max = self._parse_var() or self._parse_primary()
7553        else:
7554            max = self._parse_var() or self._parse_primary()
7555            min = exp.Literal.number(0)
7556        self._match_r_paren()
7557        return self.expression(exp.DictRange, this=this, min=min, max=max)
7558
7559    def _parse_comprehension(
7560        self, this: t.Optional[exp.Expression]
7561    ) -> t.Optional[exp.Comprehension]:
7562        index = self._index
7563        expression = self._parse_column()
7564        if not self._match(TokenType.IN):
7565            self._retreat(index - 1)
7566            return None
7567        iterator = self._parse_column()
7568        condition = self._parse_assignment() if self._match_text_seq("IF") else None
7569        return self.expression(
7570            exp.Comprehension,
7571            this=this,
7572            expression=expression,
7573            iterator=iterator,
7574            condition=condition,
7575        )
7576
7577    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
7578        if self._match(TokenType.HEREDOC_STRING):
7579            return self.expression(exp.Heredoc, this=self._prev.text)
7580
7581        if not self._match_text_seq("$"):
7582            return None
7583
7584        tags = ["$"]
7585        tag_text = None
7586
7587        if self._is_connected():
7588            self._advance()
7589            tags.append(self._prev.text.upper())
7590        else:
7591            self.raise_error("No closing $ found")
7592
7593        if tags[-1] != "$":
7594            if self._is_connected() and self._match_text_seq("$"):
7595                tag_text = tags[-1]
7596                tags.append("$")
7597            else:
7598                self.raise_error("No closing $ found")
7599
7600        heredoc_start = self._curr
7601
7602        while self._curr:
7603            if self._match_text_seq(*tags, advance=False):
7604                this = self._find_sql(heredoc_start, self._prev)
7605                self._advance(len(tags))
7606                return self.expression(exp.Heredoc, this=this, tag=tag_text)
7607
7608            self._advance()
7609
7610        self.raise_error(f"No closing {''.join(tags)} found")
7611        return None
7612
7613    def _find_parser(
7614        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
7615    ) -> t.Optional[t.Callable]:
7616        if not self._curr:
7617            return None
7618
7619        index = self._index
7620        this = []
7621        while True:
7622            # The current token might be multiple words
7623            curr = self._curr.text.upper()
7624            key = curr.split(" ")
7625            this.append(curr)
7626
7627            self._advance()
7628            result, trie = in_trie(trie, key)
7629            if result == TrieResult.FAILED:
7630                break
7631
7632            if result == TrieResult.EXISTS:
7633                subparser = parsers[" ".join(this)]
7634                return subparser
7635
7636        self._retreat(index)
7637        return None
7638
7639    def _match(self, token_type, advance=True, expression=None):
7640        if not self._curr:
7641            return None
7642
7643        if self._curr.token_type == token_type:
7644            if advance:
7645                self._advance()
7646            self._add_comments(expression)
7647            return True
7648
7649        return None
7650
7651    def _match_set(self, types, advance=True):
7652        if not self._curr:
7653            return None
7654
7655        if self._curr.token_type in types:
7656            if advance:
7657                self._advance()
7658            return True
7659
7660        return None
7661
7662    def _match_pair(self, token_type_a, token_type_b, advance=True):
7663        if not self._curr or not self._next:
7664            return None
7665
7666        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
7667            if advance:
7668                self._advance(2)
7669            return True
7670
7671        return None
7672
7673    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
7674        if not self._match(TokenType.L_PAREN, expression=expression):
7675            self.raise_error("Expecting (")
7676
7677    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
7678        if not self._match(TokenType.R_PAREN, expression=expression):
7679            self.raise_error("Expecting )")
7680
7681    def _match_texts(self, texts, advance=True):
7682        if (
7683            self._curr
7684            and self._curr.token_type != TokenType.STRING
7685            and self._curr.text.upper() in texts
7686        ):
7687            if advance:
7688                self._advance()
7689            return True
7690        return None
7691
7692    def _match_text_seq(self, *texts, advance=True):
7693        index = self._index
7694        for text in texts:
7695            if (
7696                self._curr
7697                and self._curr.token_type != TokenType.STRING
7698                and self._curr.text.upper() == text
7699            ):
7700                self._advance()
7701            else:
7702                self._retreat(index)
7703                return None
7704
7705        if not advance:
7706            self._retreat(index)
7707
7708        return True
7709
7710    def _replace_lambda(
7711        self, node: t.Optional[exp.Expression], expressions: t.List[exp.Expression]
7712    ) -> t.Optional[exp.Expression]:
7713        if not node:
7714            return node
7715
7716        lambda_types = {e.name: e.args.get("to") or False for e in expressions}
7717
7718        for column in node.find_all(exp.Column):
7719            typ = lambda_types.get(column.parts[0].name)
7720            if typ is not None:
7721                dot_or_id = column.to_dot() if column.table else column.this
7722
7723                if typ:
7724                    dot_or_id = self.expression(
7725                        exp.Cast,
7726                        this=dot_or_id,
7727                        to=typ,
7728                    )
7729
7730                parent = column.parent
7731
7732                while isinstance(parent, exp.Dot):
7733                    if not isinstance(parent.parent, exp.Dot):
7734                        parent.replace(dot_or_id)
7735                        break
7736                    parent = parent.parent
7737                else:
7738                    if column is node:
7739                        node = dot_or_id
7740                    else:
7741                        column.replace(dot_or_id)
7742        return node
7743
7744    def _parse_truncate_table(self) -> t.Optional[exp.TruncateTable] | exp.Expression:
7745        start = self._prev
7746
7747        # Not to be confused with TRUNCATE(number, decimals) function call
7748        if self._match(TokenType.L_PAREN):
7749            self._retreat(self._index - 2)
7750            return self._parse_function()
7751
7752        # Clickhouse supports TRUNCATE DATABASE as well
7753        is_database = self._match(TokenType.DATABASE)
7754
7755        self._match(TokenType.TABLE)
7756
7757        exists = self._parse_exists(not_=False)
7758
7759        expressions = self._parse_csv(
7760            lambda: self._parse_table(schema=True, is_db_reference=is_database)
7761        )
7762
7763        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
7764
7765        if self._match_text_seq("RESTART", "IDENTITY"):
7766            identity = "RESTART"
7767        elif self._match_text_seq("CONTINUE", "IDENTITY"):
7768            identity = "CONTINUE"
7769        else:
7770            identity = None
7771
7772        if self._match_text_seq("CASCADE") or self._match_text_seq("RESTRICT"):
7773            option = self._prev.text
7774        else:
7775            option = None
7776
7777        partition = self._parse_partition()
7778
7779        # Fallback case
7780        if self._curr:
7781            return self._parse_as_command(start)
7782
7783        return self.expression(
7784            exp.TruncateTable,
7785            expressions=expressions,
7786            is_database=is_database,
7787            exists=exists,
7788            cluster=cluster,
7789            identity=identity,
7790            option=option,
7791            partition=partition,
7792        )
7793
7794    def _parse_with_operator(self) -> t.Optional[exp.Expression]:
7795        this = self._parse_ordered(self._parse_opclass)
7796
7797        if not self._match(TokenType.WITH):
7798            return this
7799
7800        op = self._parse_var(any_token=True)
7801
7802        return self.expression(exp.WithOperator, this=this, op=op)
7803
7804    def _parse_wrapped_options(self) -> t.List[t.Optional[exp.Expression]]:
7805        self._match(TokenType.EQ)
7806        self._match(TokenType.L_PAREN)
7807
7808        opts: t.List[t.Optional[exp.Expression]] = []
7809        while self._curr and not self._match(TokenType.R_PAREN):
7810            if self._match_text_seq("FORMAT_NAME", "="):
7811                # The FORMAT_NAME can be set to an identifier for Snowflake and T-SQL,
7812                # so we parse it separately to use _parse_field()
7813                prop = self.expression(
7814                    exp.Property, this=exp.var("FORMAT_NAME"), value=self._parse_field()
7815                )
7816                opts.append(prop)
7817            else:
7818                opts.append(self._parse_property())
7819
7820            self._match(TokenType.COMMA)
7821
7822        return opts
7823
7824    def _parse_copy_parameters(self) -> t.List[exp.CopyParameter]:
7825        sep = TokenType.COMMA if self.dialect.COPY_PARAMS_ARE_CSV else None
7826
7827        options = []
7828        while self._curr and not self._match(TokenType.R_PAREN, advance=False):
7829            option = self._parse_var(any_token=True)
7830            prev = self._prev.text.upper()
7831
7832            # Different dialects might separate options and values by white space, "=" and "AS"
7833            self._match(TokenType.EQ)
7834            self._match(TokenType.ALIAS)
7835
7836            param = self.expression(exp.CopyParameter, this=option)
7837
7838            if prev in self.COPY_INTO_VARLEN_OPTIONS and self._match(
7839                TokenType.L_PAREN, advance=False
7840            ):
7841                # Snowflake FILE_FORMAT case, Databricks COPY & FORMAT options
7842                param.set("expressions", self._parse_wrapped_options())
7843            elif prev == "FILE_FORMAT":
7844                # T-SQL's external file format case
7845                param.set("expression", self._parse_field())
7846            else:
7847                param.set("expression", self._parse_unquoted_field())
7848
7849            options.append(param)
7850            self._match(sep)
7851
7852        return options
7853
7854    def _parse_credentials(self) -> t.Optional[exp.Credentials]:
7855        expr = self.expression(exp.Credentials)
7856
7857        if self._match_text_seq("STORAGE_INTEGRATION", "="):
7858            expr.set("storage", self._parse_field())
7859        if self._match_text_seq("CREDENTIALS"):
7860            # Snowflake case: CREDENTIALS = (...), Redshift case: CREDENTIALS <string>
7861            creds = (
7862                self._parse_wrapped_options() if self._match(TokenType.EQ) else self._parse_field()
7863            )
7864            expr.set("credentials", creds)
7865        if self._match_text_seq("ENCRYPTION"):
7866            expr.set("encryption", self._parse_wrapped_options())
7867        if self._match_text_seq("IAM_ROLE"):
7868            expr.set("iam_role", self._parse_field())
7869        if self._match_text_seq("REGION"):
7870            expr.set("region", self._parse_field())
7871
7872        return expr
7873
7874    def _parse_file_location(self) -> t.Optional[exp.Expression]:
7875        return self._parse_field()
7876
7877    def _parse_copy(self) -> exp.Copy | exp.Command:
7878        start = self._prev
7879
7880        self._match(TokenType.INTO)
7881
7882        this = (
7883            self._parse_select(nested=True, parse_subquery_alias=False)
7884            if self._match(TokenType.L_PAREN, advance=False)
7885            else self._parse_table(schema=True)
7886        )
7887
7888        kind = self._match(TokenType.FROM) or not self._match_text_seq("TO")
7889
7890        files = self._parse_csv(self._parse_file_location)
7891        credentials = self._parse_credentials()
7892
7893        self._match_text_seq("WITH")
7894
7895        params = self._parse_wrapped(self._parse_copy_parameters, optional=True)
7896
7897        # Fallback case
7898        if self._curr:
7899            return self._parse_as_command(start)
7900
7901        return self.expression(
7902            exp.Copy,
7903            this=this,
7904            kind=kind,
7905            credentials=credentials,
7906            files=files,
7907            params=params,
7908        )
7909
7910    def _parse_normalize(self) -> exp.Normalize:
7911        return self.expression(
7912            exp.Normalize,
7913            this=self._parse_bitwise(),
7914            form=self._match(TokenType.COMMA) and self._parse_var(),
7915        )
7916
7917    def _parse_ceil_floor(self, expr_type: t.Type[TCeilFloor]) -> TCeilFloor:
7918        args = self._parse_csv(lambda: self._parse_lambda())
7919
7920        this = seq_get(args, 0)
7921        decimals = seq_get(args, 1)
7922
7923        return expr_type(
7924            this=this, decimals=decimals, to=self._match_text_seq("TO") and self._parse_var()
7925        )
7926
7927    def _parse_star_ops(self) -> t.Optional[exp.Expression]:
7928        if self._match_text_seq("COLUMNS", "(", advance=False):
7929            this = self._parse_function()
7930            if isinstance(this, exp.Columns):
7931                this.set("unpack", True)
7932            return this
7933
7934        return self.expression(
7935            exp.Star,
7936            **{  # type: ignore
7937                "except": self._parse_star_op("EXCEPT", "EXCLUDE"),
7938                "replace": self._parse_star_op("REPLACE"),
7939                "rename": self._parse_star_op("RENAME"),
7940            },
7941        )
7942
7943    def _parse_grant_privilege(self) -> t.Optional[exp.GrantPrivilege]:
7944        privilege_parts = []
7945
7946        # Keep consuming consecutive keywords until comma (end of this privilege) or ON
7947        # (end of privilege list) or L_PAREN (start of column list) are met
7948        while self._curr and not self._match_set(self.PRIVILEGE_FOLLOW_TOKENS, advance=False):
7949            privilege_parts.append(self._curr.text.upper())
7950            self._advance()
7951
7952        this = exp.var(" ".join(privilege_parts))
7953        expressions = (
7954            self._parse_wrapped_csv(self._parse_column)
7955            if self._match(TokenType.L_PAREN, advance=False)
7956            else None
7957        )
7958
7959        return self.expression(exp.GrantPrivilege, this=this, expressions=expressions)
7960
7961    def _parse_grant_principal(self) -> t.Optional[exp.GrantPrincipal]:
7962        kind = self._match_texts(("ROLE", "GROUP")) and self._prev.text.upper()
7963        principal = self._parse_id_var()
7964
7965        if not principal:
7966            return None
7967
7968        return self.expression(exp.GrantPrincipal, this=principal, kind=kind)
7969
7970    def _parse_grant(self) -> exp.Grant | exp.Command:
7971        start = self._prev
7972
7973        privileges = self._parse_csv(self._parse_grant_privilege)
7974
7975        self._match(TokenType.ON)
7976        kind = self._match_set(self.CREATABLES) and self._prev.text.upper()
7977
7978        # Attempt to parse the securable e.g. MySQL allows names
7979        # such as "foo.*", "*.*" which are not easily parseable yet
7980        securable = self._try_parse(self._parse_table_parts)
7981
7982        if not securable or not self._match_text_seq("TO"):
7983            return self._parse_as_command(start)
7984
7985        principals = self._parse_csv(self._parse_grant_principal)
7986
7987        grant_option = self._match_text_seq("WITH", "GRANT", "OPTION")
7988
7989        if self._curr:
7990            return self._parse_as_command(start)
7991
7992        return self.expression(
7993            exp.Grant,
7994            privileges=privileges,
7995            kind=kind,
7996            securable=securable,
7997            principals=principals,
7998            grant_option=grant_option,
7999        )
8000
8001    def _parse_overlay(self) -> exp.Overlay:
8002        return self.expression(
8003            exp.Overlay,
8004            **{  # type: ignore
8005                "this": self._parse_bitwise(),
8006                "expression": self._match_text_seq("PLACING") and self._parse_bitwise(),
8007                "from": self._match_text_seq("FROM") and self._parse_bitwise(),
8008                "for": self._match_text_seq("FOR") and self._parse_bitwise(),
8009            },
8010        )

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)
1451    def __init__(
1452        self,
1453        error_level: t.Optional[ErrorLevel] = None,
1454        error_message_context: int = 100,
1455        max_errors: int = 3,
1456        dialect: DialectType = None,
1457    ):
1458        from sqlglot.dialects import Dialect
1459
1460        self.error_level = error_level or ErrorLevel.IMMEDIATE
1461        self.error_message_context = error_message_context
1462        self.max_errors = max_errors
1463        self.dialect = Dialect.get_or_raise(dialect)
1464        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'>>, 'CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Contains'>>, 'CONVERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Convert'>>, 'CONVERT_TIMEZONE': <function build_convert_timezone>, 'CORR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Corr'>>, 'COUNT': <function Parser.<lambda>>, 'COUNT_IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, 'COUNTIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CountIf'>>, 'COVAR_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CovarPop'>>, 'COVAR_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CovarSamp'>>, 'CURRENT_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDate'>>, 'CURRENT_DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CurrentDatetime'>>, 'CURRENT_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'>>, 'FEATURES_AT_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FeaturesAtTime'>>, 'FIRST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.First'>>, 'FIRST_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FirstValue'>>, 'FLATTEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Flatten'>>, 'FLOOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Floor'>>, 'FROM_BASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase'>>, 'FROM_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase64'>>, 'FROM_ISO8601_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromISO8601Timestamp'>>, 'GAP_FILL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GapFill'>>, 'GENERATE_DATE_ARRAY': <function Parser.<lambda>>, 'GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateSeries'>>, 'GENERATE_TIMESTAMP_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateTimestampArray'>>, 'GREATEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Greatest'>>, 'GROUP_CONCAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GroupConcat'>>, 'HEX': <function build_hex>, 'HLL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Hll'>>, 'IF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.If'>>, 'IIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.If'>>, 'INITCAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Initcap'>>, 'INLINE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Inline'>>, 'INT64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Int64'>>, 'IS_ASCII': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsAscii'>>, 'IS_INF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsInf'>>, 'ISINF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsInf'>>, 'IS_NAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsNan'>>, 'ISNAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.IsNan'>>, 'J_S_O_N_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArray'>>, 'J_S_O_N_ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayAgg'>>, 'JSON_ARRAY_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONArrayContains'>>, 'JSONB_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBContains'>>, 'JSONB_EXISTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExists'>>, 'JSONB_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtract'>>, 'JSONB_EXTRACT_SCALAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONBExtractScalar'>>, 'J_S_O_N_EXISTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExists'>>, 'JSON_EXTRACT': <function build_extract_json_with_path.<locals>._builder>, 'JSON_EXTRACT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExtractArray'>>, 'JSON_EXTRACT_SCALAR': <function build_extract_json_with_path.<locals>._builder>, 'JSON_FORMAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONFormat'>>, 'J_S_O_N_OBJECT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObject'>>, 'J_S_O_N_OBJECT_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObjectAgg'>>, 'J_S_O_N_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONTable'>>, 'J_S_O_N_VALUE_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONValueArray'>>, 'LAG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lag'>>, 'LAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Last'>>, 'LAST_DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastValue'>>, 'LEAD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lead'>>, 'LEAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Least'>>, 'LEFT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Left'>>, 'LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'CHAR_LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'CHARACTER_LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEVENSHTEIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Levenshtein'>>, 'LIST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.List'>>, 'LN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ln'>>, 'LOG': <function build_logarithm>, 'LOGICAL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOLAND_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'LOGICAL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOLOR_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'LOWER': <function build_lower>, 'LCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'LOWER_HEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LowerHex'>>, 'MD5': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5'>>, 'MD5_DIGEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5Digest'>>, 'MAKE_INTERVAL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MakeInterval'>>, 'MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Map'>>, 'MAP_FROM_ENTRIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MapFromEntries'>>, 'MATCH_AGAINST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MatchAgainst'>>, 'MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Max'>>, 'MEDIAN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Median'>>, 'MIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Min'>>, 'MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Month'>>, 'MONTHS_BETWEEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MonthsBetween'>>, 'NEXT_VALUE_FOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NextValueFor'>>, 'NORMALIZE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Normalize'>>, 'NTH_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NthValue'>>, 'NULLIF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nullif'>>, 'NUMBER_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.NumberToStr'>>, 'NVL2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Nvl2'>>, 'OBJECT_INSERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ObjectInsert'>>, 'OPEN_J_S_O_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.OpenJSON'>>, 'OVERLAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Overlay'>>, 'PAD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pad'>>, 'PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParameterizedAgg'>>, 'PARSE_JSON': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'JSON_PARSE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'PERCENTILE_CONT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileCont'>>, 'PERCENTILE_DISC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileDisc'>>, 'POSEXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Posexplode'>>, 'POSEXPLODE_OUTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PosexplodeOuter'>>, 'POWER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'POW': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'PREDICT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Predict'>>, 'QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quantile'>>, 'QUARTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quarter'>>, 'RAND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rand'>>, 'RANDOM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rand'>>, 'RANDN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Randn'>>, 'RANGE_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RangeN'>>, 'READ_CSV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ReadCSV'>>, 'REDUCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Reduce'>>, 'REGEXP_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpExtract'>>, 'REGEXP_EXTRACT_ALL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpExtractAll'>>, 'REGEXP_I_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpILike'>>, 'REGEXP_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpLike'>>, 'REGEXP_REPLACE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpReplace'>>, 'REGEXP_SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpSplit'>>, 'REPEAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Repeat'>>, 'RIGHT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Right'>>, 'ROUND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Round'>>, 'ROW_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RowNumber'>>, 'SHA': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA1': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA2'>>, 'SAFE_DIVIDE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeDivide'>>, 'SIGN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SIGNUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SORT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SortArray'>>, 'SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Split'>>, 'SPLIT_PART': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SplitPart'>>, 'SQRT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sqrt'>>, 'STANDARD_HASH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StandardHash'>>, 'STAR_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StarMap'>>, 'STARTS_WITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STARTSWITH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StartsWith'>>, 'STDDEV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stddev'>>, 'STDEV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stddev'>>, 'STDDEV_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevPop'>>, 'STDDEV_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StddevSamp'>>, 'STR_POSITION': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToDate'>>, 'STR_TO_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToMap'>>, 'STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToTime'>>, 'STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrToUnix'>>, 'STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.String'>>, 'STRING_TO_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StringToArray'>>, 'SPLIT_BY_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StringToArray'>>, 'STRUCT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Struct'>>, 'STRUCT_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StructExtract'>>, 'STUFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'INSERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Stuff'>>, 'SUBSTRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Substring'>>, 'SUBSTR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Substring'>>, 'SUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sum'>>, 'TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Time'>>, 'TIME_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeAdd'>>, 'TIME_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeDiff'>>, 'TIME_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeFromParts'>>, 'TIMEFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeFromParts'>>, 'TIME_STR_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToDate'>>, 'TIME_STR_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToTime'>>, 'TIME_STR_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeStrToUnix'>>, 'TIME_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeSub'>>, 'TIME_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToStr'>>, 'TIME_TO_TIME_STR': <function Parser.<lambda>>, 'TIME_TO_UNIX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeToUnix'>>, 'TIME_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimeTrunc'>>, 'TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Timestamp'>>, 'TIMESTAMP_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampAdd'>>, 'TIMESTAMPDIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampDiff'>>, 'TIMESTAMP_FROM_PARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, 'TIMESTAMPFROMPARTS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampFromParts'>>, 'TIMESTAMP_SUB': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampSub'>>, 'TIMESTAMP_TRUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TimestampTrunc'>>, 'TO_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToArray'>>, 'TO_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToBase64'>>, 'TO_CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToChar'>>, 'TO_DAYS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToDays'>>, 'TO_DOUBLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToDouble'>>, 'TO_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToMap'>>, 'TO_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToNumber'>>, 'TRANSFORM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Transform'>>, 'TRIM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Trim'>>, 'TRY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Try'>>, 'TRY_CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TryCast'>>, 'TS_OR_DI_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDiToDi'>>, 'TS_OR_DS_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsAdd'>>, 'TS_OR_DS_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsDiff'>>, 'TS_OR_DS_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToDate'>>, 'TS_OR_DS_TO_DATE_STR': <function Parser.<lambda>>, 'TS_OR_DS_TO_DATETIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToDatetime'>>, 'TS_OR_DS_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTime'>>, 'TS_OR_DS_TO_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTimestamp'>>, 'UNHEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unhex'>>, 'UNICODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unicode'>>, 'UNIX_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixDate'>>, 'UNIX_SECONDS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixSeconds'>>, 'UNIX_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToStr'>>, 'UNIX_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTime'>>, 'UNIX_TO_TIME_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTimeStr'>>, 'UNNEST': <function Parser.<lambda>>, 'UPPER': <function build_upper>, 'UCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Upper'>>, 'UUID': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Uuid'>>, 'GEN_RANDOM_UUID': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Uuid'>>, 'GENERATE_UUID': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Uuid'>>, 'UUID_STRING': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Uuid'>>, 'VAR_MAP': <function build_var_map>, 'VARIANCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VAR_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'VAR_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Week'>>, 'WEEK_OF_YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'WEEKOFYEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'XMLELEMENT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.XMLElement'>>, 'X_M_L_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.XMLTable'>>, 'XOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Xor'>>, 'YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Year'>>, 'ARRAYAGG': <function Parser.<lambda>>, 'GLOB': <function Parser.<lambda>>, 'JSON_EXTRACT_PATH_TEXT': <function build_extract_json_with_path.<locals>._builder>, 'LIKE': <function build_like>, 'LOG2': <function Parser.<lambda>>, 'LOG10': <function Parser.<lambda>>, 'LPAD': <function Parser.<lambda>>, 'LEFTPAD': <function Parser.<lambda>>, 'LTRIM': <function Parser.<lambda>>, 'MOD': <function build_mod>, 'RIGHTPAD': <function Parser.<lambda>>, 'RPAD': <function Parser.<lambda>>, 'RTRIM': <function Parser.<lambda>>, 'SCOPE_RESOLUTION': <function Parser.<lambda>>, 'STRPOS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'CHARINDEX': <function Parser.<lambda>>, 'INSTR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.StrPosition'>>, 'LOCATE': <function Parser.<lambda>>, 'TO_HEX': <function build_hex>}
NO_PAREN_FUNCTIONS = {<TokenType.CURRENT_DATE: 'CURRENT_DATE'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>: <class 'sqlglot.expressions.CurrentTime'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>: <class 'sqlglot.expressions.CurrentTimestamp'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>: <class 'sqlglot.expressions.CurrentUser'>}
STRUCT_TYPE_TOKENS = {<TokenType.UNION: 'UNION'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.OBJECT: 'OBJECT'>}
NESTED_TYPE_TOKENS = {<TokenType.NULLABLE: 'NULLABLE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.UNION: 'UNION'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.LIST: 'LIST'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.MAP: 'MAP'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM: 'ENUM'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.DYNAMIC: 'DYNAMIC'>}
AGGREGATE_TYPE_TOKENS = {<TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>}
TYPE_TOKENS = {<TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.UNION: 'UNION'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.INT: 'INT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT128: 'INT128'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NAME: 'NAME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.RING: 'RING'>, <TokenType.DATE: 'DATE'>, <TokenType.NULL: 'NULL'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UINT: 'UINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INET: 'INET'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.YEAR: 'YEAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TEXT: 'TEXT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CHAR: 'CHAR'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.LIST: 'LIST'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.XML: 'XML'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.NESTED: 'NESTED'>, <TokenType.BIT: 'BIT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.RANGE: 'RANGE'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UUID: 'UUID'>, <TokenType.MAP: 'MAP'>}
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.L_BRACKET: 'L_BRACKET'>, <TokenType.STAR: 'STAR'>, <TokenType.SELECT: 'SELECT'>, <TokenType.PLUS: 'PLUS'>, <TokenType.HASH: 'HASH'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.COMMA: 'COMMA'>, <TokenType.SLASH: 'SLASH'>, <TokenType.DOT: 'DOT'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.CARET: 'CARET'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.TILDA: 'TILDA'>, <TokenType.EQ: 'EQ'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.AMP: 'AMP'>, <TokenType.NOT: 'NOT'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.GT: 'GT'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.COLON: 'COLON'>, <TokenType.LT: 'LT'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.MOD: 'MOD'>, <TokenType.PIPE: 'PIPE'>, <TokenType.DASH: 'DASH'>}
DB_CREATABLES = {<TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.TAG: 'TAG'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.VIEW: 'VIEW'>, <TokenType.MODEL: 'MODEL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.TABLE: 'TABLE'>, <TokenType.SINK: 'SINK'>}
CREATABLES = {<TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.TAG: 'TAG'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SINK: 'SINK'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.MODEL: 'MODEL'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.TABLE: 'TABLE'>}
ALTERABLES = {<TokenType.VIEW: 'VIEW'>, <TokenType.INDEX: 'INDEX'>, <TokenType.TABLE: 'TABLE'>}
ID_VAR_TOKENS = {<TokenType.NEXT: 'NEXT'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.ROW: 'ROW'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CASE: 'CASE'>, <TokenType.TIME: 'TIME'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ASC: 'ASC'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.SET: 'SET'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT: 'INT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.FULL: 'FULL'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.COPY: 'COPY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.INT128: 'INT128'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TOP: 'TOP'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.RENAME: 'RENAME'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.NAME: 'NAME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ANY: 'ANY'>, <TokenType.RING: 'RING'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.DATE: 'DATE'>, <TokenType.NULL: 'NULL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.KILL: 'KILL'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DIV: 'DIV'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UINT: 'UINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.VAR: 'VAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SOME: 'SOME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INET: 'INET'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.FALSE: 'FALSE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DETACH: 'DETACH'>, <TokenType.YEAR: 'YEAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TEXT: 'TEXT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.ASOF: 'ASOF'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INDEX: 'INDEX'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.USE: 'USE'>, <TokenType.TAG: 'TAG'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.LIST: 'LIST'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DESC: 'DESC'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.END: 'END'>, <TokenType.XML: 'XML'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.FILTER: 'FILTER'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IS: 'IS'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.BIT: 'BIT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.SINK: 'SINK'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ALL: 'ALL'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UUID: 'UUID'>, <TokenType.ROWS: 'ROWS'>, <TokenType.MAP: 'MAP'>}
INTERVAL_VARS = {<TokenType.NEXT: 'NEXT'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.ROW: 'ROW'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CASE: 'CASE'>, <TokenType.TIME: 'TIME'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ASC: 'ASC'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.SET: 'SET'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT: 'INT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.FULL: 'FULL'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.COPY: 'COPY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.INT128: 'INT128'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TOP: 'TOP'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.RENAME: 'RENAME'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.NAME: 'NAME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ANY: 'ANY'>, <TokenType.RING: 'RING'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.DATE: 'DATE'>, <TokenType.NULL: 'NULL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.KILL: 'KILL'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DIV: 'DIV'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UINT: 'UINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.VAR: 'VAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SOME: 'SOME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INET: 'INET'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.FALSE: 'FALSE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DETACH: 'DETACH'>, <TokenType.YEAR: 'YEAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TEXT: 'TEXT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.ASOF: 'ASOF'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INDEX: 'INDEX'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.USE: 'USE'>, <TokenType.TAG: 'TAG'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.LIST: 'LIST'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DESC: 'DESC'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.XML: 'XML'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.FILTER: 'FILTER'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IS: 'IS'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.BIT: 'BIT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.SINK: 'SINK'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ALL: 'ALL'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UUID: 'UUID'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.MAP: 'MAP'>}
TABLE_ALIAS_TOKENS = {<TokenType.NEXT: 'NEXT'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.ROW: 'ROW'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CASE: 'CASE'>, <TokenType.TIME: 'TIME'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ASC: 'ASC'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.SET: 'SET'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT: 'INT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.COPY: 'COPY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.INT128: 'INT128'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TOP: 'TOP'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.RENAME: 'RENAME'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.NAME: 'NAME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ANY: 'ANY'>, <TokenType.RING: 'RING'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DATE: 'DATE'>, <TokenType.NULL: 'NULL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.KILL: 'KILL'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DIV: 'DIV'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UINT: 'UINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.VAR: 'VAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SOME: 'SOME'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INET: 'INET'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.FALSE: 'FALSE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DETACH: 'DETACH'>, <TokenType.YEAR: 'YEAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TEXT: 'TEXT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INDEX: 'INDEX'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.USE: 'USE'>, <TokenType.TAG: 'TAG'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.LIST: 'LIST'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DESC: 'DESC'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.END: 'END'>, <TokenType.XML: 'XML'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.FILTER: 'FILTER'>, <TokenType.IS: 'IS'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.BIT: 'BIT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.SINK: 'SINK'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ALL: 'ALL'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UUID: 'UUID'>, <TokenType.MAP: 'MAP'>}
ALIAS_TOKENS = {<TokenType.NEXT: 'NEXT'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.ROW: 'ROW'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CASE: 'CASE'>, <TokenType.TIME: 'TIME'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ASC: 'ASC'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.SET: 'SET'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT: 'INT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.FULL: 'FULL'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.COPY: 'COPY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.INT128: 'INT128'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TOP: 'TOP'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.RENAME: 'RENAME'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.NAME: 'NAME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ANY: 'ANY'>, <TokenType.RING: 'RING'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.DATE: 'DATE'>, <TokenType.NULL: 'NULL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.KILL: 'KILL'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DIV: 'DIV'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UINT: 'UINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.VAR: 'VAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SOME: 'SOME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INET: 'INET'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.FALSE: 'FALSE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DETACH: 'DETACH'>, <TokenType.YEAR: 'YEAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TEXT: 'TEXT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.ASOF: 'ASOF'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INDEX: 'INDEX'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.USE: 'USE'>, <TokenType.TAG: 'TAG'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.LIST: 'LIST'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DESC: 'DESC'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.END: 'END'>, <TokenType.XML: 'XML'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.FILTER: 'FILTER'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IS: 'IS'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.BIT: 'BIT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.SINK: 'SINK'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ALL: 'ALL'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UUID: 'UUID'>, <TokenType.ROWS: 'ROWS'>, <TokenType.MAP: 'MAP'>}
ARRAY_CONSTRUCTORS = {'ARRAY': <class 'sqlglot.expressions.Array'>, 'LIST': <class 'sqlglot.expressions.List'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.NEXT: 'NEXT'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.ROW: 'ROW'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CASE: 'CASE'>, <TokenType.TIME: 'TIME'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ASC: 'ASC'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.SET: 'SET'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT: 'INT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.COPY: 'COPY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.INT128: 'INT128'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TOP: 'TOP'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.RENAME: 'RENAME'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.NAME: 'NAME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ANY: 'ANY'>, <TokenType.RING: 'RING'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DATE: 'DATE'>, <TokenType.NULL: 'NULL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.KILL: 'KILL'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DIV: 'DIV'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UINT: 'UINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.VAR: 'VAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SOME: 'SOME'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INET: 'INET'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.FALSE: 'FALSE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DETACH: 'DETACH'>, <TokenType.YEAR: 'YEAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TEXT: 'TEXT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INDEX: 'INDEX'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.USE: 'USE'>, <TokenType.TAG: 'TAG'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.LIST: 'LIST'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DESC: 'DESC'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.END: 'END'>, <TokenType.XML: 'XML'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.FILTER: 'FILTER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.BIT: 'BIT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.SINK: 'SINK'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ALL: 'ALL'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UUID: 'UUID'>, <TokenType.ROWS: 'ROWS'>, <TokenType.MAP: 'MAP'>}
UPDATE_ALIAS_TOKENS = {<TokenType.NEXT: 'NEXT'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.ROW: 'ROW'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CASE: 'CASE'>, <TokenType.TIME: 'TIME'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ASC: 'ASC'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT: 'INT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.COPY: 'COPY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.INT128: 'INT128'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TOP: 'TOP'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.RENAME: 'RENAME'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.NAME: 'NAME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ANY: 'ANY'>, <TokenType.RING: 'RING'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.DATE: 'DATE'>, <TokenType.NULL: 'NULL'>, <TokenType.FIRST: 'FIRST'>, <TokenType.KILL: 'KILL'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DIV: 'DIV'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UINT: 'UINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.VAR: 'VAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SOME: 'SOME'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INET: 'INET'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.FALSE: 'FALSE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DETACH: 'DETACH'>, <TokenType.YEAR: 'YEAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TEXT: 'TEXT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INDEX: 'INDEX'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.USE: 'USE'>, <TokenType.TAG: 'TAG'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.LIST: 'LIST'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DESC: 'DESC'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.END: 'END'>, <TokenType.XML: 'XML'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.FILTER: 'FILTER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.IS: 'IS'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.BIT: 'BIT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.SINK: 'SINK'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ALL: 'ALL'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UUID: 'UUID'>, <TokenType.ROWS: 'ROWS'>, <TokenType.MAP: 'MAP'>}
TRIM_TYPES = {'LEADING', 'BOTH', 'TRAILING'}
FUNC_TOKENS = {<TokenType.NEXT: 'NEXT'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.ROW: 'ROW'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TIME: 'TIME'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.UNION: 'UNION'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.INT: 'INT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.BINARY: 'BINARY'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.INT128: 'INT128'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.NAME: 'NAME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ANY: 'ANY'>, <TokenType.RING: 'RING'>, <TokenType.DATE: 'DATE'>, <TokenType.NULL: 'NULL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UINT: 'UINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.VAR: 'VAR'>, <TokenType.LIKE: 'LIKE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SOME: 'SOME'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INET: 'INET'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.YEAR: 'YEAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.INSERT: 'INSERT'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.CHAR: 'CHAR'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INDEX: 'INDEX'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.LIST: 'LIST'>, <TokenType.XOR: 'XOR'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.XML: 'XML'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.FILTER: 'FILTER'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.NESTED: 'NESTED'>, <TokenType.BIT: 'BIT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ALL: 'ALL'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.GLOB: 'GLOB'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UUID: 'UUID'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.MAP: 'MAP'>}
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.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIMETZ: 'TIMETZ'>}
SET_OPERATIONS = {<TokenType.INTERSECT: 'INTERSECT'>, <TokenType.UNION: 'UNION'>, <TokenType.EXCEPT: 'EXCEPT'>}
JOIN_METHODS = {<TokenType.NATURAL: 'NATURAL'>, <TokenType.POSITIONAL: 'POSITIONAL'>, <TokenType.ASOF: 'ASOF'>}
JOIN_SIDES = {<TokenType.LEFT: 'LEFT'>, <TokenType.FULL: 'FULL'>, <TokenType.RIGHT: 'RIGHT'>}
JOIN_KINDS = {<TokenType.ANTI: 'ANTI'>, <TokenType.STRAIGHT_JOIN: 'STRAIGHT_JOIN'>, <TokenType.CROSS: 'CROSS'>, <TokenType.SEMI: 'SEMI'>, <TokenType.OUTER: 'OUTER'>, <TokenType.INNER: 'INNER'>}
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.Hint'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Identifier'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Join'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lambda'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lateral'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Limit'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Offset'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Order'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Ordered'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Properties'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Qualify'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Returning'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Select'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Sort'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Table'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.TableAlias'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Tuple'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Whens'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Where'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Window'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.With'>: <function Parser.<lambda>>, 'JOIN_TYPE': <function Parser.<lambda>>}
STATEMENT_PARSERS = {<TokenType.ALTER: 'ALTER'>: <function Parser.<lambda>>, <TokenType.ANALYZE: 'ANALYZE'>: <function Parser.<lambda>>, <TokenType.BEGIN: 'BEGIN'>: <function Parser.<lambda>>, <TokenType.CACHE: 'CACHE'>: <function Parser.<lambda>>, <TokenType.COMMENT: 'COMMENT'>: <function Parser.<lambda>>, <TokenType.COMMIT: 'COMMIT'>: <function Parser.<lambda>>, <TokenType.COPY: 'COPY'>: <function Parser.<lambda>>, <TokenType.CREATE: 'CREATE'>: <function Parser.<lambda>>, <TokenType.DELETE: 'DELETE'>: <function Parser.<lambda>>, <TokenType.DESC: 'DESC'>: <function Parser.<lambda>>, <TokenType.DESCRIBE: 'DESCRIBE'>: <function Parser.<lambda>>, <TokenType.DROP: 'DROP'>: <function Parser.<lambda>>, <TokenType.GRANT: 'GRANT'>: <function Parser.<lambda>>, <TokenType.INSERT: 'INSERT'>: <function Parser.<lambda>>, <TokenType.KILL: 'KILL'>: <function Parser.<lambda>>, <TokenType.LOAD: 'LOAD'>: <function Parser.<lambda>>, <TokenType.MERGE: 'MERGE'>: <function Parser.<lambda>>, <TokenType.PIVOT: 'PIVOT'>: <function Parser.<lambda>>, <TokenType.PRAGMA: 'PRAGMA'>: <function Parser.<lambda>>, <TokenType.REFRESH: 'REFRESH'>: <function Parser.<lambda>>, <TokenType.ROLLBACK: 'ROLLBACK'>: <function Parser.<lambda>>, <TokenType.SET: 'SET'>: <function Parser.<lambda>>, <TokenType.TRUNCATE: 'TRUNCATE'>: <function Parser.<lambda>>, <TokenType.UNCACHE: 'UNCACHE'>: <function Parser.<lambda>>, <TokenType.UNPIVOT: 'UNPIVOT'>: <function Parser.<lambda>>, <TokenType.UPDATE: 'UPDATE'>: <function Parser.<lambda>>, <TokenType.USE: 'USE'>: <function Parser.<lambda>>, <TokenType.SEMICOLON: 'SEMICOLON'>: <function Parser.<lambda>>}
UNARY_PARSERS = {<TokenType.PLUS: 'PLUS'>: <function Parser.<lambda>>, <TokenType.NOT: 'NOT'>: <function Parser.<lambda>>, <TokenType.TILDA: 'TILDA'>: <function Parser.<lambda>>, <TokenType.DASH: 'DASH'>: <function Parser.<lambda>>, <TokenType.PIPE_SLASH: 'PIPE_SLASH'>: <function Parser.<lambda>>, <TokenType.DPIPE_SLASH: 'DPIPE_SLASH'>: <function Parser.<lambda>>}
STRING_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>}
NUMERIC_PARSERS = {<TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>}
PRIMARY_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>, <TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>, <TokenType.INTRODUCER: 'INTRODUCER'>: <function Parser.<lambda>>, <TokenType.NULL: 'NULL'>: <function Parser.<lambda>>, <TokenType.TRUE: 'TRUE'>: <function Parser.<lambda>>, <TokenType.FALSE: 'FALSE'>: <function Parser.<lambda>>, <TokenType.SESSION_PARAMETER: 'SESSION_PARAMETER'>: <function Parser.<lambda>>, <TokenType.STAR: 'STAR'>: <function Parser.<lambda>>}
PLACEHOLDER_PARSERS = {<TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>, <TokenType.PARAMETER: 'PARAMETER'>: <function Parser.<lambda>>, <TokenType.COLON: 'COLON'>: <function Parser.<lambda>>}
RANGE_PARSERS = {<TokenType.AT_GT: 'AT_GT'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.BETWEEN: 'BETWEEN'>: <function Parser.<lambda>>, <TokenType.GLOB: 'GLOB'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.ILIKE: 'ILIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.IN: 'IN'>: <function Parser.<lambda>>, <TokenType.IRLIKE: 'IRLIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.IS: 'IS'>: <function Parser.<lambda>>, <TokenType.LIKE: 'LIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.LT_AT: 'LT_AT'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.OVERLAPS: 'OVERLAPS'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.RLIKE: 'RLIKE'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.SIMILAR_TO: 'SIMILAR_TO'>: <function binary_range_parser.<locals>._parse_binary_range>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>}
PROPERTY_PARSERS: Dict[str, Callable] = {'ALLOWED_VALUES': <function Parser.<lambda>>, 'ALGORITHM': <function Parser.<lambda>>, 'AUTO': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'BACKUP': <function Parser.<lambda>>, 'BLOCKCOMPRESSION': <function Parser.<lambda>>, 'CHARSET': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECKSUM': <function Parser.<lambda>>, 'CLUSTER BY': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'CONTAINS': <function Parser.<lambda>>, 'COPY': <function Parser.<lambda>>, 'DATABLOCKSIZE': <function Parser.<lambda>>, 'DATA_DELETION': <function Parser.<lambda>>, 'DEFINER': <function Parser.<lambda>>, 'DETERMINISTIC': <function Parser.<lambda>>, 'DISTRIBUTED': <function Parser.<lambda>>, 'DUPLICATE': <function Parser.<lambda>>, 'DYNAMIC': <function Parser.<lambda>>, 'DISTKEY': <function Parser.<lambda>>, 'DISTSTYLE': <function Parser.<lambda>>, 'EMPTY': <function Parser.<lambda>>, 'ENGINE': <function Parser.<lambda>>, 'EXECUTE': <function Parser.<lambda>>, 'EXTERNAL': <function Parser.<lambda>>, 'FALLBACK': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'FREESPACE': <function Parser.<lambda>>, 'GLOBAL': <function Parser.<lambda>>, 'HEAP': <function Parser.<lambda>>, 'ICEBERG': <function Parser.<lambda>>, 'IMMUTABLE': <function Parser.<lambda>>, 'INHERITS': <function Parser.<lambda>>, 'INPUT': <function Parser.<lambda>>, 'JOURNAL': <function Parser.<lambda>>, 'LANGUAGE': <function Parser.<lambda>>, 'LAYOUT': <function Parser.<lambda>>, 'LIFETIME': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'LOCATION': <function Parser.<lambda>>, 'LOCK': <function Parser.<lambda>>, 'LOCKING': <function Parser.<lambda>>, 'LOG': <function Parser.<lambda>>, 'MATERIALIZED': <function Parser.<lambda>>, 'MERGEBLOCKRATIO': <function Parser.<lambda>>, 'MODIFIES': <function Parser.<lambda>>, 'MULTISET': <function Parser.<lambda>>, 'NO': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'ORDER BY': <function Parser.<lambda>>, 'OUTPUT': <function Parser.<lambda>>, 'PARTITION': <function Parser.<lambda>>, 'PARTITION BY': <function Parser.<lambda>>, 'PARTITIONED BY': <function Parser.<lambda>>, 'PARTITIONED_BY': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'RANGE': <function Parser.<lambda>>, 'READS': <function Parser.<lambda>>, 'REMOTE': <function Parser.<lambda>>, 'RETURNS': <function Parser.<lambda>>, 'STRICT': <function Parser.<lambda>>, 'STREAMING': <function Parser.<lambda>>, 'ROW': <function Parser.<lambda>>, 'ROW_FORMAT': <function Parser.<lambda>>, 'SAMPLE': <function Parser.<lambda>>, 'SECURE': <function Parser.<lambda>>, 'SECURITY': <function Parser.<lambda>>, 'SET': <function Parser.<lambda>>, 'SETTINGS': <function Parser.<lambda>>, 'SHARING': <function Parser.<lambda>>, 'SORTKEY': <function Parser.<lambda>>, 'SOURCE': <function Parser.<lambda>>, 'STABLE': <function Parser.<lambda>>, 'STORED': <function Parser.<lambda>>, 'SYSTEM_VERSIONING': <function Parser.<lambda>>, 'TBLPROPERTIES': <function Parser.<lambda>>, 'TEMP': <function Parser.<lambda>>, 'TEMPORARY': <function Parser.<lambda>>, 'TO': <function Parser.<lambda>>, 'TRANSIENT': <function Parser.<lambda>>, 'TRANSFORM': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'USING': <function Parser.<lambda>>, 'UNLOGGED': <function Parser.<lambda>>, 'VOLATILE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
CONSTRAINT_PARSERS = {'AUTOINCREMENT': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'CASESPECIFIC': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECK': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'COMPRESS': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'NONCLUSTERED': <function Parser.<lambda>>, 'DEFAULT': <function Parser.<lambda>>, 'ENCODE': <function Parser.<lambda>>, 'EPHEMERAL': <function Parser.<lambda>>, 'EXCLUDE': <function Parser.<lambda>>, 'FOREIGN KEY': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'GENERATED': <function Parser.<lambda>>, 'IDENTITY': <function Parser.<lambda>>, 'INLINE': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'NOT': <function Parser.<lambda>>, 'NULL': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'PATH': <function Parser.<lambda>>, 'PERIOD': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'REFERENCES': <function Parser.<lambda>>, 'TITLE': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'UNIQUE': <function Parser.<lambda>>, 'UPPERCASE': <function Parser.<lambda>>, 'WATERMARK': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
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 = {'CHECK', 'PRIMARY KEY', 'EXCLUDE', 'UNIQUE', 'FOREIGN KEY', 'PERIOD', 'WATERMARK', 'LIKE'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.STRING: 'STRING'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
KEY_VALUE_DEFINITIONS = (<class 'sqlglot.expressions.Alias'>, <class 'sqlglot.expressions.EQ'>, <class 'sqlglot.expressions.PropertyEQ'>, <class 'sqlglot.expressions.Slice'>)
FUNCTION_PARSERS = {'CAST': <function Parser.<lambda>>, 'CEIL': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'FLOOR': <function Parser.<lambda>>, 'GAP_FILL': <function Parser.<lambda>>, 'JSON_OBJECT': <function Parser.<lambda>>, 'JSON_OBJECTAGG': <function Parser.<lambda>>, 'JSON_TABLE': <function Parser.<lambda>>, 'MATCH': <function Parser.<lambda>>, 'NORMALIZE': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'OVERLAY': <function Parser.<lambda>>, 'POSITION': <function Parser.<lambda>>, 'PREDICT': <function Parser.<lambda>>, 'SAFE_CAST': <function Parser.<lambda>>, 'STRING_AGG': <function Parser.<lambda>>, 'SUBSTRING': <function Parser.<lambda>>, 'TRIM': <function Parser.<lambda>>, 'TRY_CAST': <function Parser.<lambda>>, 'TRY_CONVERT': <function Parser.<lambda>>, 'XMLELEMENT': <function Parser.<lambda>>, 'XMLTABLE': <function Parser.<lambda>>}
QUERY_MODIFIER_PARSERS = {<TokenType.MATCH_RECOGNIZE: 'MATCH_RECOGNIZE'>: <function Parser.<lambda>>, <TokenType.PREWHERE: 'PREWHERE'>: <function Parser.<lambda>>, <TokenType.WHERE: 'WHERE'>: <function Parser.<lambda>>, <TokenType.GROUP_BY: 'GROUP_BY'>: <function Parser.<lambda>>, <TokenType.HAVING: 'HAVING'>: <function Parser.<lambda>>, <TokenType.QUALIFY: 'QUALIFY'>: <function Parser.<lambda>>, <TokenType.WINDOW: 'WINDOW'>: <function Parser.<lambda>>, <TokenType.ORDER_BY: 'ORDER_BY'>: <function Parser.<lambda>>, <TokenType.LIMIT: 'LIMIT'>: <function Parser.<lambda>>, <TokenType.FETCH: 'FETCH'>: <function Parser.<lambda>>, <TokenType.OFFSET: 'OFFSET'>: <function Parser.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>, <TokenType.LOCK: 'LOCK'>: <function Parser.<lambda>>, <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>: <function Parser.<lambda>>, <TokenType.USING: 'USING'>: <function Parser.<lambda>>, <TokenType.CLUSTER_BY: 'CLUSTER_BY'>: <function Parser.<lambda>>, <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>: <function Parser.<lambda>>, <TokenType.SORT_BY: 'SORT_BY'>: <function Parser.<lambda>>, <TokenType.CONNECT_BY: 'CONNECT_BY'>: <function Parser.<lambda>>, <TokenType.START_WITH: 'START_WITH'>: <function Parser.<lambda>>}
SET_PARSERS = {'GLOBAL': <function Parser.<lambda>>, 'LOCAL': <function Parser.<lambda>>, 'SESSION': <function Parser.<lambda>>, 'TRANSACTION': <function Parser.<lambda>>}
SHOW_PARSERS: Dict[str, Callable] = {}
TYPE_LITERAL_PARSERS = {<Type.JSON: 'JSON'>: <function Parser.<lambda>>}
DDL_SELECT_TOKENS = {<TokenType.L_PAREN: 'L_PAREN'>, <TokenType.SELECT: 'SELECT'>, <TokenType.WITH: 'WITH'>}
PRE_VOLATILE_TOKENS = {<TokenType.REPLACE: 'REPLACE'>, <TokenType.CREATE: 'CREATE'>, <TokenType.UNIQUE: 'UNIQUE'>}
TRANSACTION_KIND = {'DEFERRED', 'IMMEDIATE', 'EXCLUSIVE'}
TRANSACTION_CHARACTERISTICS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ISOLATION': (('LEVEL', 'REPEATABLE', 'READ'), ('LEVEL', 'READ', 'COMMITTED'), ('LEVEL', 'READ', 'UNCOMITTED'), ('LEVEL', 'SERIALIZABLE')), 'READ': ('WRITE', 'ONLY')}
CONFLICT_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ABORT': (), 'FAIL': (), 'IGNORE': (), 'REPLACE': (), 'ROLLBACK': (), 'UPDATE': (), 'DO': ('NOTHING', 'UPDATE')}
CREATE_SEQUENCE: Dict[str, Sequence[Union[Sequence[str], str]]] = {'SCALE': ('EXTEND', 'NOEXTEND'), 'SHARD': ('EXTEND', 'NOEXTEND'), 'NO': ('CYCLE', 'CACHE', 'MAXVALUE', 'MINVALUE'), 'SESSION': (), 'GLOBAL': (), 'KEEP': (), 'NOKEEP': (), 'ORDER': (), 'NOORDER': (), 'NOCACHE': (), 'CYCLE': (), 'NOCYCLE': (), 'NOMINVALUE': (), 'NOMAXVALUE': (), 'NOSCALE': (), 'NOSHARD': ()}
ISOLATED_LOADING_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'FOR': ('ALL', 'INSERT', 'NONE')}
USABLES: Dict[str, Sequence[Union[Sequence[str], str]]] = {'ROLE': (), 'WAREHOUSE': (), 'DATABASE': (), 'SCHEMA': (), 'CATALOG': ()}
CAST_ACTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'RENAME': ('FIELDS',), 'ADD': ('FIELDS',)}
SCHEMA_BINDING_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'TYPE': ('EVOLUTION',), 'BINDING': (), 'COMPENSATION': (), 'EVOLUTION': ()}
PROCEDURE_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {}
EXECUTE_AS_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'CALLER': (), 'SELF': (), 'OWNER': ()}
KEY_CONSTRAINT_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'NOT': ('ENFORCED',), 'MATCH': ('FULL', 'PARTIAL', 'SIMPLE'), 'INITIALLY': ('DEFERRED', 'IMMEDIATE'), 'DEFERRABLE': (), 'NORELY': ()}
INSERT_ALTERNATIVES = {'FAIL', 'REPLACE', 'ROLLBACK', 'ABORT', 'IGNORE'}
CLONE_KEYWORDS = {'COPY', 'CLONE'}
HISTORICAL_DATA_PREFIX = {'BEFORE', 'END', 'AT'}
HISTORICAL_DATA_KIND = {'OFFSET', 'TIMESTAMP', 'STATEMENT', 'STREAM'}
OPCLASS_FOLLOW_KEYWORDS = {'NULLS', 'WITH', 'DESC', 'ASC'}
OPTYPE_FOLLOW_TOKENS = {<TokenType.COMMA: 'COMMA'>, <TokenType.R_PAREN: 'R_PAREN'>}
TABLE_INDEX_HINT_TOKENS = {<TokenType.USE: 'USE'>, <TokenType.FORCE: 'FORCE'>, <TokenType.IGNORE: 'IGNORE'>}
VIEW_ATTRIBUTES = {'VIEW_METADATA', 'SCHEMABINDING', 'ENCRYPTION'}
WINDOW_ALIAS_TOKENS = {<TokenType.NEXT: 'NEXT'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.ROW: 'ROW'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CASE: 'CASE'>, <TokenType.TIME: 'TIME'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ASC: 'ASC'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.SET: 'SET'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT: 'INT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.FULL: 'FULL'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.COPY: 'COPY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.INT128: 'INT128'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TOP: 'TOP'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.RENAME: 'RENAME'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.NAME: 'NAME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ANY: 'ANY'>, <TokenType.RING: 'RING'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.DATE: 'DATE'>, <TokenType.NULL: 'NULL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.KILL: 'KILL'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DIV: 'DIV'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UINT: 'UINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.VAR: 'VAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SOME: 'SOME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INET: 'INET'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.FALSE: 'FALSE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DETACH: 'DETACH'>, <TokenType.YEAR: 'YEAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TEXT: 'TEXT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.ASOF: 'ASOF'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INDEX: 'INDEX'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.USE: 'USE'>, <TokenType.TAG: 'TAG'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.LIST: 'LIST'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DESC: 'DESC'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.END: 'END'>, <TokenType.XML: 'XML'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.FILTER: 'FILTER'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IS: 'IS'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.BIT: 'BIT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.SINK: 'SINK'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ALL: 'ALL'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UUID: 'UUID'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.MAP: 'MAP'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'PRECEDING', 'FOLLOWING'}
JSON_KEY_VALUE_SEPARATOR_TOKENS = {<TokenType.COMMA: 'COMMA'>, <TokenType.IS: 'IS'>, <TokenType.COLON: 'COLON'>}
FETCH_TOKENS = {<TokenType.NEXT: 'NEXT'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CASE: 'CASE'>, <TokenType.TIME: 'TIME'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ASC: 'ASC'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.SET: 'SET'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT: 'INT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.FULL: 'FULL'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.COPY: 'COPY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.INT128: 'INT128'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TOP: 'TOP'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.RENAME: 'RENAME'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.NAME: 'NAME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ANY: 'ANY'>, <TokenType.RING: 'RING'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.DATE: 'DATE'>, <TokenType.NULL: 'NULL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.KILL: 'KILL'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DIV: 'DIV'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UINT: 'UINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.VAR: 'VAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SOME: 'SOME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INET: 'INET'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.FALSE: 'FALSE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DETACH: 'DETACH'>, <TokenType.YEAR: 'YEAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TEXT: 'TEXT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.ASOF: 'ASOF'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INDEX: 'INDEX'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.USE: 'USE'>, <TokenType.TAG: 'TAG'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.LIST: 'LIST'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DESC: 'DESC'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.END: 'END'>, <TokenType.XML: 'XML'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.FILTER: 'FILTER'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IS: 'IS'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.BIT: 'BIT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.SINK: 'SINK'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ALL: 'ALL'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UUID: 'UUID'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.MAP: 'MAP'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.KEY: 'KEY'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.NEXT: 'NEXT'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.ROW: 'ROW'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.POINT: 'POINT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CASE: 'CASE'>, <TokenType.TIME: 'TIME'>, <TokenType.LOAD: 'LOAD'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.JSONB: 'JSONB'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SOURCE: 'SOURCE'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.ASC: 'ASC'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.MODEL: 'MODEL'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.SET: 'SET'>, <TokenType.VIEW: 'VIEW'>, <TokenType.INT: 'INT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.FULL: 'FULL'>, <TokenType.JSON: 'JSON'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.COPY: 'COPY'>, <TokenType.BINARY: 'BINARY'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.INT128: 'INT128'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TOP: 'TOP'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.LINESTRING: 'LINESTRING'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.RENAME: 'RENAME'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.NAME: 'NAME'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.MONEY: 'MONEY'>, <TokenType.DATE32: 'DATE32'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.ANY: 'ANY'>, <TokenType.RING: 'RING'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.DATE: 'DATE'>, <TokenType.NULL: 'NULL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.FIRST: 'FIRST'>, <TokenType.KILL: 'KILL'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.LIMIT: 'LIMIT'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.DIV: 'DIV'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.DECIMAL128: 'DECIMAL128'>, <TokenType.UINT: 'UINT'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.VAR: 'VAR'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.SOME: 'SOME'>, <TokenType.ANTI: 'ANTI'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.IPV4: 'IPV4'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.INET: 'INET'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.DATETIME2: 'DATETIME2'>, <TokenType.FALSE: 'FALSE'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.DETACH: 'DETACH'>, <TokenType.YEAR: 'YEAR'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.TEXT: 'TEXT'>, <TokenType.KEEP: 'KEEP'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.ATTACH: 'ATTACH'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.ASOF: 'ASOF'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.INDEX: 'INDEX'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.USE: 'USE'>, <TokenType.TAG: 'TAG'>, <TokenType.CACHE: 'CACHE'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.MULTIPOLYGON: 'MULTIPOLYGON'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.MULTILINESTRING: 'MULTILINESTRING'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SHOW: 'SHOW'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.SMALLDATETIME: 'SMALLDATETIME'>, <TokenType.DECIMAL256: 'DECIMAL256'>, <TokenType.LIST: 'LIST'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.DECIMAL64: 'DECIMAL64'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.APPLY: 'APPLY'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.NAMESPACE: 'NAMESPACE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DESC: 'DESC'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.END: 'END'>, <TokenType.XML: 'XML'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.FILTER: 'FILTER'>, <TokenType.SEMI: 'SEMI'>, <TokenType.IS: 'IS'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.DECIMAL32: 'DECIMAL32'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.DYNAMIC: 'DYNAMIC'>, <TokenType.POLYGON: 'POLYGON'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.BIT: 'BIT'>, <TokenType.INT256: 'INT256'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.FINAL: 'FINAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.SUPER: 'SUPER'>, <TokenType.SINK: 'SINK'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.RANGE: 'RANGE'>, <TokenType.ALL: 'ALL'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UUID: 'UUID'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.MAP: 'MAP'>}
SELECT_START_TOKENS = {<TokenType.L_PAREN: 'L_PAREN'>, <TokenType.SELECT: 'SELECT'>, <TokenType.WITH: 'WITH'>}
COPY_INTO_VARLEN_OPTIONS = {'FILE_FORMAT', 'COPY_OPTIONS', 'CREDENTIAL', 'FORMAT_OPTIONS'}
IS_JSON_PREDICATE_KIND = {'ARRAY', 'OBJECT', 'SCALAR', 'VALUE'}
ODBC_DATETIME_LITERALS = {'d': <class 'sqlglot.expressions.Date'>, 't': <class 'sqlglot.expressions.Time'>, 'ts': <class 'sqlglot.expressions.Timestamp'>}
ON_CONDITION_TOKENS = {'TRUE', 'NULL', 'ERROR', 'EMPTY', 'FALSE'}
PRIVILEGE_FOLLOW_TOKENS = {<TokenType.L_PAREN: 'L_PAREN'>, <TokenType.COMMA: 'COMMA'>, <TokenType.ON: 'ON'>}
DESCRIBE_STYLES = {'FORMATTED', 'EXTENDED', 'HISTORY', 'ANALYZE'}
ANALYZE_STYLES = {'SAMPLE', 'VERBOSE', 'LOCAL', 'FULL', 'SKIP_LOCKED', 'NO_WRITE_TO_BINLOG', 'BUFFER_USAGE_LIMIT'}
ANALYZE_EXPRESSION_PARSERS = {'ALL': <function Parser.<lambda>>, 'COMPUTE': <function Parser.<lambda>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'ESTIMATE': <function Parser.<lambda>>, 'LIST': <function Parser.<lambda>>, 'PREDICATE': <function Parser.<lambda>>, 'UPDATE': <function Parser.<lambda>>, 'VALIDATE': <function Parser.<lambda>>}
PARTITION_KEYWORDS = {'SUBPARTITION', 'PARTITION'}
AMBIGUOUS_ALIAS_TOKENS = (<TokenType.LIMIT: 'LIMIT'>, <TokenType.OFFSET: 'OFFSET'>)
OPERATION_MODIFIERS: Set[str] = set()
STRICT_CAST = True
PREFIXED_PIVOT_COLUMNS = False
IDENTIFY_PIVOT_STRINGS = False
LOG_DEFAULTS_TO_LN = False
ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
TABLESAMPLE_CSV = False
DEFAULT_SAMPLING_METHOD: Optional[str] = None
SET_REQUIRES_ASSIGNMENT_DELIMITER = True
TRIM_PATTERN_FIRST = False
STRING_ALIASES = False
MODIFIERS_ATTACHED_TO_SET_OP = True
SET_OP_MODIFIERS = {'order', 'offset', 'limit'}
NO_PAREN_IF_COMMANDS = True
JSON_ARROWS_REQUIRE_JSON_TYPE = False
COLON_IS_VARIANT_EXTRACT = False
VALUES_FOLLOWED_BY_PAREN = True
SUPPORTS_IMPLICIT_UNNEST = False
INTERVAL_SPANS = True
SUPPORTS_PARTITION_SELECTION = False
WRAPPED_TRANSFORM_COLUMN_CONSTRAINT = True
OPTIONAL_ALIAS_TOKEN_CTE = True
SHOW_TRIE: Dict = {}
SET_TRIE: Dict = {'GLOBAL': {0: True}, 'LOCAL': {0: True}, 'SESSION': {0: True}, 'TRANSACTION': {0: True}}
error_level
error_message_context
max_errors
dialect
def reset(self):
1466    def reset(self):
1467        self.sql = ""
1468        self.errors = []
1469        self._tokens = []
1470        self._index = 0
1471        self._curr = None
1472        self._next = None
1473        self._prev = None
1474        self._prev_comments = None
def parse( self, raw_tokens: List[sqlglot.tokens.Token], sql: Optional[str] = None) -> List[Optional[sqlglot.expressions.Expression]]:
1476    def parse(
1477        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1478    ) -> t.List[t.Optional[exp.Expression]]:
1479        """
1480        Parses a list of tokens and returns a list of syntax trees, one tree
1481        per parsed SQL statement.
1482
1483        Args:
1484            raw_tokens: The list of tokens.
1485            sql: The original SQL string, used to produce helpful debug messages.
1486
1487        Returns:
1488            The list of the produced syntax trees.
1489        """
1490        return self._parse(
1491            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1492        )

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]]:
1494    def parse_into(
1495        self,
1496        expression_types: exp.IntoType,
1497        raw_tokens: t.List[Token],
1498        sql: t.Optional[str] = None,
1499    ) -> t.List[t.Optional[exp.Expression]]:
1500        """
1501        Parses a list of tokens into a given Expression type. If a collection of Expression
1502        types is given instead, this method will try to parse the token list into each one
1503        of them, stopping at the first for which the parsing succeeds.
1504
1505        Args:
1506            expression_types: The expression type(s) to try and parse the token list into.
1507            raw_tokens: The list of tokens.
1508            sql: The original SQL string, used to produce helpful debug messages.
1509
1510        Returns:
1511            The target Expression.
1512        """
1513        errors = []
1514        for expression_type in ensure_list(expression_types):
1515            parser = self.EXPRESSION_PARSERS.get(expression_type)
1516            if not parser:
1517                raise TypeError(f"No parser registered for {expression_type}")
1518
1519            try:
1520                return self._parse(parser, raw_tokens, sql)
1521            except ParseError as e:
1522                e.errors[0]["into_expression"] = expression_type
1523                errors.append(e)
1524
1525        raise ParseError(
1526            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1527            errors=merge_errors(errors),
1528        ) 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:
1568    def check_errors(self) -> None:
1569        """Logs or raises any found errors, depending on the chosen error level setting."""
1570        if self.error_level == ErrorLevel.WARN:
1571            for error in self.errors:
1572                logger.error(str(error))
1573        elif self.error_level == ErrorLevel.RAISE and self.errors:
1574            raise ParseError(
1575                concat_messages(self.errors, self.max_errors),
1576                errors=merge_errors(self.errors),
1577            )

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:
1579    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1580        """
1581        Appends an error in the list of recorded errors or raises it, depending on the chosen
1582        error level setting.
1583        """
1584        token = token or self._curr or self._prev or Token.string("")
1585        start = token.start
1586        end = token.end + 1
1587        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1588        highlight = self.sql[start:end]
1589        end_context = self.sql[end : end + self.error_message_context]
1590
1591        error = ParseError.new(
1592            f"{message}. Line {token.line}, Col: {token.col}.\n"
1593            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1594            description=message,
1595            line=token.line,
1596            col=token.col,
1597            start_context=start_context,
1598            highlight=highlight,
1599            end_context=end_context,
1600        )
1601
1602        if self.error_level == ErrorLevel.IMMEDIATE:
1603            raise error
1604
1605        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:
1607    def expression(
1608        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1609    ) -> E:
1610        """
1611        Creates a new, validated Expression.
1612
1613        Args:
1614            exp_class: The expression class to instantiate.
1615            comments: An optional list of comments to attach to the expression.
1616            kwargs: The arguments to set for the expression along with their respective values.
1617
1618        Returns:
1619            The target expression.
1620        """
1621        instance = exp_class(**kwargs)
1622        instance.add_comments(comments) if comments else self._add_comments(instance)
1623        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:
1630    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1631        """
1632        Validates an Expression, making sure that all its mandatory arguments are set.
1633
1634        Args:
1635            expression: The expression to validate.
1636            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1637
1638        Returns:
1639            The validated expression.
1640        """
1641        if self.error_level != ErrorLevel.IGNORE:
1642            for error_message in expression.error_messages(args):
1643                self.raise_error(error_message)
1644
1645        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