Edit on GitHub

sqlglot.parser

   1from __future__ import annotations
   2
   3import logging
   4import typing as t
   5from collections import defaultdict
   6
   7from sqlglot import exp
   8from sqlglot.errors import ErrorLevel, ParseError, concat_messages, merge_errors
   9from sqlglot.helper import apply_index_offset, ensure_list, seq_get
  10from sqlglot.time import format_time
  11from sqlglot.tokens import Token, Tokenizer, TokenType
  12from sqlglot.trie import TrieResult, in_trie, new_trie
  13
  14if t.TYPE_CHECKING:
  15    from sqlglot._typing import E, Lit
  16    from sqlglot.dialects.dialect import Dialect, DialectType
  17
  18    T = t.TypeVar("T")
  19
  20logger = logging.getLogger("sqlglot")
  21
  22OPTIONS_TYPE = t.Dict[str, t.Sequence[t.Union[t.Sequence[str], str]]]
  23
  24
  25def build_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
  26    if len(args) == 1 and args[0].is_star:
  27        return exp.StarMap(this=args[0])
  28
  29    keys = []
  30    values = []
  31    for i in range(0, len(args), 2):
  32        keys.append(args[i])
  33        values.append(args[i + 1])
  34
  35    return exp.VarMap(keys=exp.array(*keys, copy=False), values=exp.array(*values, copy=False))
  36
  37
  38def build_like(args: t.List) -> exp.Escape | exp.Like:
  39    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
  40    return exp.Escape(this=like, expression=seq_get(args, 2)) if len(args) > 2 else like
  41
  42
  43def binary_range_parser(
  44    expr_type: t.Type[exp.Expression], reverse_args: bool = False
  45) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
  46    def _parse_binary_range(
  47        self: Parser, this: t.Optional[exp.Expression]
  48    ) -> t.Optional[exp.Expression]:
  49        expression = self._parse_bitwise()
  50        if reverse_args:
  51            this, expression = expression, this
  52        return self._parse_escape(self.expression(expr_type, this=this, expression=expression))
  53
  54    return _parse_binary_range
  55
  56
  57def build_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
  58    # Default argument order is base, expression
  59    this = seq_get(args, 0)
  60    expression = seq_get(args, 1)
  61
  62    if expression:
  63        if not dialect.LOG_BASE_FIRST:
  64            this, expression = expression, this
  65        return exp.Log(this=this, expression=expression)
  66
  67    return (exp.Ln if dialect.parser_class.LOG_DEFAULTS_TO_LN else exp.Log)(this=this)
  68
  69
  70def build_hex(args: t.List, dialect: Dialect) -> exp.Hex | exp.LowerHex:
  71    arg = seq_get(args, 0)
  72    return exp.LowerHex(this=arg) if dialect.HEX_LOWERCASE else exp.Hex(this=arg)
  73
  74
  75def build_lower(args: t.List) -> exp.Lower | exp.Hex:
  76    # LOWER(HEX(..)) can be simplified to LowerHex to simplify its transpilation
  77    arg = seq_get(args, 0)
  78    return exp.LowerHex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Lower(this=arg)
  79
  80
  81def build_upper(args: t.List) -> exp.Upper | exp.Hex:
  82    # UPPER(HEX(..)) can be simplified to Hex to simplify its transpilation
  83    arg = seq_get(args, 0)
  84    return exp.Hex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Upper(this=arg)
  85
  86
  87def build_extract_json_with_path(expr_type: t.Type[E]) -> t.Callable[[t.List, Dialect], E]:
  88    def _builder(args: t.List, dialect: Dialect) -> E:
  89        expression = expr_type(
  90            this=seq_get(args, 0), expression=dialect.to_json_path(seq_get(args, 1))
  91        )
  92        if len(args) > 2 and expr_type is exp.JSONExtract:
  93            expression.set("expressions", args[2:])
  94
  95        return expression
  96
  97    return _builder
  98
  99
 100def build_mod(args: t.List) -> exp.Mod:
 101    this = seq_get(args, 0)
 102    expression = seq_get(args, 1)
 103
 104    # Wrap the operands if they are binary nodes, e.g. MOD(a + 1, 7) -> (a + 1) % 7
 105    this = exp.Paren(this=this) if isinstance(this, exp.Binary) else this
 106    expression = exp.Paren(this=expression) if isinstance(expression, exp.Binary) else expression
 107
 108    return exp.Mod(this=this, expression=expression)
 109
 110
 111def build_pad(args: t.List, is_left: bool = True):
 112    return exp.Pad(
 113        this=seq_get(args, 0),
 114        expression=seq_get(args, 1),
 115        fill_pattern=seq_get(args, 2),
 116        is_left=is_left,
 117    )
 118
 119
 120class _Parser(type):
 121    def __new__(cls, clsname, bases, attrs):
 122        klass = super().__new__(cls, clsname, bases, attrs)
 123
 124        klass.SHOW_TRIE = new_trie(key.split(" ") for key in klass.SHOW_PARSERS)
 125        klass.SET_TRIE = new_trie(key.split(" ") for key in klass.SET_PARSERS)
 126
 127        return klass
 128
 129
 130class Parser(metaclass=_Parser):
 131    """
 132    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
 133
 134    Args:
 135        error_level: The desired error level.
 136            Default: ErrorLevel.IMMEDIATE
 137        error_message_context: The amount of context to capture from a query string when displaying
 138            the error message (in number of characters).
 139            Default: 100
 140        max_errors: Maximum number of error messages to include in a raised ParseError.
 141            This is only relevant if error_level is ErrorLevel.RAISE.
 142            Default: 3
 143    """
 144
 145    FUNCTIONS: t.Dict[str, t.Callable] = {
 146        **{name: func.from_arg_list for name, func in exp.FUNCTION_BY_NAME.items()},
 147        "CONCAT": lambda args, dialect: exp.Concat(
 148            expressions=args,
 149            safe=not dialect.STRICT_STRING_CONCAT,
 150            coalesce=dialect.CONCAT_COALESCE,
 151        ),
 152        "CONCAT_WS": lambda args, dialect: exp.ConcatWs(
 153            expressions=args,
 154            safe=not dialect.STRICT_STRING_CONCAT,
 155            coalesce=dialect.CONCAT_COALESCE,
 156        ),
 157        "DATE_TO_DATE_STR": lambda args: exp.Cast(
 158            this=seq_get(args, 0),
 159            to=exp.DataType(this=exp.DataType.Type.TEXT),
 160        ),
 161        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
 162        "HEX": build_hex,
 163        "JSON_EXTRACT": build_extract_json_with_path(exp.JSONExtract),
 164        "JSON_EXTRACT_SCALAR": build_extract_json_with_path(exp.JSONExtractScalar),
 165        "JSON_EXTRACT_PATH_TEXT": build_extract_json_with_path(exp.JSONExtractScalar),
 166        "LIKE": build_like,
 167        "LOG": build_logarithm,
 168        "LOG2": lambda args: exp.Log(this=exp.Literal.number(2), expression=seq_get(args, 0)),
 169        "LOG10": lambda args: exp.Log(this=exp.Literal.number(10), expression=seq_get(args, 0)),
 170        "LOWER": build_lower,
 171        "LPAD": lambda args: build_pad(args),
 172        "LEFTPAD": lambda args: build_pad(args),
 173        "MOD": build_mod,
 174        "RPAD": lambda args: build_pad(args, is_left=False),
 175        "RIGHTPAD": lambda args: build_pad(args, is_left=False),
 176        "SCOPE_RESOLUTION": lambda args: exp.ScopeResolution(expression=seq_get(args, 0))
 177        if len(args) != 2
 178        else exp.ScopeResolution(this=seq_get(args, 0), expression=seq_get(args, 1)),
 179        "TIME_TO_TIME_STR": lambda args: exp.Cast(
 180            this=seq_get(args, 0),
 181            to=exp.DataType(this=exp.DataType.Type.TEXT),
 182        ),
 183        "TO_HEX": build_hex,
 184        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
 185            this=exp.Cast(
 186                this=seq_get(args, 0),
 187                to=exp.DataType(this=exp.DataType.Type.TEXT),
 188            ),
 189            start=exp.Literal.number(1),
 190            length=exp.Literal.number(10),
 191        ),
 192        "UNNEST": lambda args: exp.Unnest(expressions=ensure_list(seq_get(args, 0))),
 193        "UPPER": build_upper,
 194        "VAR_MAP": build_var_map,
 195    }
 196
 197    NO_PAREN_FUNCTIONS = {
 198        TokenType.CURRENT_DATE: exp.CurrentDate,
 199        TokenType.CURRENT_DATETIME: exp.CurrentDate,
 200        TokenType.CURRENT_TIME: exp.CurrentTime,
 201        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
 202        TokenType.CURRENT_USER: exp.CurrentUser,
 203    }
 204
 205    STRUCT_TYPE_TOKENS = {
 206        TokenType.NESTED,
 207        TokenType.OBJECT,
 208        TokenType.STRUCT,
 209    }
 210
 211    NESTED_TYPE_TOKENS = {
 212        TokenType.ARRAY,
 213        TokenType.LIST,
 214        TokenType.LOWCARDINALITY,
 215        TokenType.MAP,
 216        TokenType.NULLABLE,
 217        *STRUCT_TYPE_TOKENS,
 218    }
 219
 220    ENUM_TYPE_TOKENS = {
 221        TokenType.ENUM,
 222        TokenType.ENUM8,
 223        TokenType.ENUM16,
 224    }
 225
 226    AGGREGATE_TYPE_TOKENS = {
 227        TokenType.AGGREGATEFUNCTION,
 228        TokenType.SIMPLEAGGREGATEFUNCTION,
 229    }
 230
 231    TYPE_TOKENS = {
 232        TokenType.BIT,
 233        TokenType.BOOLEAN,
 234        TokenType.TINYINT,
 235        TokenType.UTINYINT,
 236        TokenType.SMALLINT,
 237        TokenType.USMALLINT,
 238        TokenType.INT,
 239        TokenType.UINT,
 240        TokenType.BIGINT,
 241        TokenType.UBIGINT,
 242        TokenType.INT128,
 243        TokenType.UINT128,
 244        TokenType.INT256,
 245        TokenType.UINT256,
 246        TokenType.MEDIUMINT,
 247        TokenType.UMEDIUMINT,
 248        TokenType.FIXEDSTRING,
 249        TokenType.FLOAT,
 250        TokenType.DOUBLE,
 251        TokenType.CHAR,
 252        TokenType.NCHAR,
 253        TokenType.VARCHAR,
 254        TokenType.NVARCHAR,
 255        TokenType.BPCHAR,
 256        TokenType.TEXT,
 257        TokenType.MEDIUMTEXT,
 258        TokenType.LONGTEXT,
 259        TokenType.MEDIUMBLOB,
 260        TokenType.LONGBLOB,
 261        TokenType.BINARY,
 262        TokenType.VARBINARY,
 263        TokenType.JSON,
 264        TokenType.JSONB,
 265        TokenType.INTERVAL,
 266        TokenType.TINYBLOB,
 267        TokenType.TINYTEXT,
 268        TokenType.TIME,
 269        TokenType.TIMETZ,
 270        TokenType.TIMESTAMP,
 271        TokenType.TIMESTAMP_S,
 272        TokenType.TIMESTAMP_MS,
 273        TokenType.TIMESTAMP_NS,
 274        TokenType.TIMESTAMPTZ,
 275        TokenType.TIMESTAMPLTZ,
 276        TokenType.TIMESTAMPNTZ,
 277        TokenType.DATETIME,
 278        TokenType.DATETIME64,
 279        TokenType.DATE,
 280        TokenType.DATE32,
 281        TokenType.INT4RANGE,
 282        TokenType.INT4MULTIRANGE,
 283        TokenType.INT8RANGE,
 284        TokenType.INT8MULTIRANGE,
 285        TokenType.NUMRANGE,
 286        TokenType.NUMMULTIRANGE,
 287        TokenType.TSRANGE,
 288        TokenType.TSMULTIRANGE,
 289        TokenType.TSTZRANGE,
 290        TokenType.TSTZMULTIRANGE,
 291        TokenType.DATERANGE,
 292        TokenType.DATEMULTIRANGE,
 293        TokenType.DECIMAL,
 294        TokenType.UDECIMAL,
 295        TokenType.BIGDECIMAL,
 296        TokenType.UUID,
 297        TokenType.GEOGRAPHY,
 298        TokenType.GEOMETRY,
 299        TokenType.HLLSKETCH,
 300        TokenType.HSTORE,
 301        TokenType.PSEUDO_TYPE,
 302        TokenType.SUPER,
 303        TokenType.SERIAL,
 304        TokenType.SMALLSERIAL,
 305        TokenType.BIGSERIAL,
 306        TokenType.XML,
 307        TokenType.YEAR,
 308        TokenType.UNIQUEIDENTIFIER,
 309        TokenType.USERDEFINED,
 310        TokenType.MONEY,
 311        TokenType.SMALLMONEY,
 312        TokenType.ROWVERSION,
 313        TokenType.IMAGE,
 314        TokenType.VARIANT,
 315        TokenType.VECTOR,
 316        TokenType.OBJECT,
 317        TokenType.OBJECT_IDENTIFIER,
 318        TokenType.INET,
 319        TokenType.IPADDRESS,
 320        TokenType.IPPREFIX,
 321        TokenType.IPV4,
 322        TokenType.IPV6,
 323        TokenType.UNKNOWN,
 324        TokenType.NULL,
 325        TokenType.NAME,
 326        TokenType.TDIGEST,
 327        *ENUM_TYPE_TOKENS,
 328        *NESTED_TYPE_TOKENS,
 329        *AGGREGATE_TYPE_TOKENS,
 330    }
 331
 332    SIGNED_TO_UNSIGNED_TYPE_TOKEN = {
 333        TokenType.BIGINT: TokenType.UBIGINT,
 334        TokenType.INT: TokenType.UINT,
 335        TokenType.MEDIUMINT: TokenType.UMEDIUMINT,
 336        TokenType.SMALLINT: TokenType.USMALLINT,
 337        TokenType.TINYINT: TokenType.UTINYINT,
 338        TokenType.DECIMAL: TokenType.UDECIMAL,
 339    }
 340
 341    SUBQUERY_PREDICATES = {
 342        TokenType.ANY: exp.Any,
 343        TokenType.ALL: exp.All,
 344        TokenType.EXISTS: exp.Exists,
 345        TokenType.SOME: exp.Any,
 346    }
 347
 348    RESERVED_TOKENS = {
 349        *Tokenizer.SINGLE_TOKENS.values(),
 350        TokenType.SELECT,
 351    } - {TokenType.IDENTIFIER}
 352
 353    DB_CREATABLES = {
 354        TokenType.DATABASE,
 355        TokenType.DICTIONARY,
 356        TokenType.MODEL,
 357        TokenType.SCHEMA,
 358        TokenType.SEQUENCE,
 359        TokenType.STORAGE_INTEGRATION,
 360        TokenType.TABLE,
 361        TokenType.TAG,
 362        TokenType.VIEW,
 363        TokenType.WAREHOUSE,
 364        TokenType.STREAMLIT,
 365    }
 366
 367    CREATABLES = {
 368        TokenType.COLUMN,
 369        TokenType.CONSTRAINT,
 370        TokenType.FOREIGN_KEY,
 371        TokenType.FUNCTION,
 372        TokenType.INDEX,
 373        TokenType.PROCEDURE,
 374        *DB_CREATABLES,
 375    }
 376
 377    # Tokens that can represent identifiers
 378    ID_VAR_TOKENS = {
 379        TokenType.ALL,
 380        TokenType.VAR,
 381        TokenType.ANTI,
 382        TokenType.APPLY,
 383        TokenType.ASC,
 384        TokenType.ASOF,
 385        TokenType.AUTO_INCREMENT,
 386        TokenType.BEGIN,
 387        TokenType.BPCHAR,
 388        TokenType.CACHE,
 389        TokenType.CASE,
 390        TokenType.COLLATE,
 391        TokenType.COMMAND,
 392        TokenType.COMMENT,
 393        TokenType.COMMIT,
 394        TokenType.CONSTRAINT,
 395        TokenType.COPY,
 396        TokenType.CUBE,
 397        TokenType.DEFAULT,
 398        TokenType.DELETE,
 399        TokenType.DESC,
 400        TokenType.DESCRIBE,
 401        TokenType.DICTIONARY,
 402        TokenType.DIV,
 403        TokenType.END,
 404        TokenType.EXECUTE,
 405        TokenType.ESCAPE,
 406        TokenType.FALSE,
 407        TokenType.FIRST,
 408        TokenType.FILTER,
 409        TokenType.FINAL,
 410        TokenType.FORMAT,
 411        TokenType.FULL,
 412        TokenType.IDENTIFIER,
 413        TokenType.IS,
 414        TokenType.ISNULL,
 415        TokenType.INTERVAL,
 416        TokenType.KEEP,
 417        TokenType.KILL,
 418        TokenType.LEFT,
 419        TokenType.LOAD,
 420        TokenType.MERGE,
 421        TokenType.NATURAL,
 422        TokenType.NEXT,
 423        TokenType.OFFSET,
 424        TokenType.OPERATOR,
 425        TokenType.ORDINALITY,
 426        TokenType.OVERLAPS,
 427        TokenType.OVERWRITE,
 428        TokenType.PARTITION,
 429        TokenType.PERCENT,
 430        TokenType.PIVOT,
 431        TokenType.PRAGMA,
 432        TokenType.RANGE,
 433        TokenType.RECURSIVE,
 434        TokenType.REFERENCES,
 435        TokenType.REFRESH,
 436        TokenType.REPLACE,
 437        TokenType.RIGHT,
 438        TokenType.ROLLUP,
 439        TokenType.ROW,
 440        TokenType.ROWS,
 441        TokenType.SEMI,
 442        TokenType.SET,
 443        TokenType.SETTINGS,
 444        TokenType.SHOW,
 445        TokenType.TEMPORARY,
 446        TokenType.TOP,
 447        TokenType.TRUE,
 448        TokenType.TRUNCATE,
 449        TokenType.UNIQUE,
 450        TokenType.UNNEST,
 451        TokenType.UNPIVOT,
 452        TokenType.UPDATE,
 453        TokenType.USE,
 454        TokenType.VOLATILE,
 455        TokenType.WINDOW,
 456        *CREATABLES,
 457        *SUBQUERY_PREDICATES,
 458        *TYPE_TOKENS,
 459        *NO_PAREN_FUNCTIONS,
 460    }
 461
 462    INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
 463
 464    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
 465        TokenType.ANTI,
 466        TokenType.APPLY,
 467        TokenType.ASOF,
 468        TokenType.FULL,
 469        TokenType.LEFT,
 470        TokenType.LOCK,
 471        TokenType.NATURAL,
 472        TokenType.OFFSET,
 473        TokenType.RIGHT,
 474        TokenType.SEMI,
 475        TokenType.WINDOW,
 476    }
 477
 478    ALIAS_TOKENS = ID_VAR_TOKENS
 479
 480    ARRAY_CONSTRUCTORS = {
 481        "ARRAY": exp.Array,
 482        "LIST": exp.List,
 483    }
 484
 485    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
 486
 487    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
 488
 489    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
 490
 491    FUNC_TOKENS = {
 492        TokenType.COLLATE,
 493        TokenType.COMMAND,
 494        TokenType.CURRENT_DATE,
 495        TokenType.CURRENT_DATETIME,
 496        TokenType.CURRENT_TIMESTAMP,
 497        TokenType.CURRENT_TIME,
 498        TokenType.CURRENT_USER,
 499        TokenType.FILTER,
 500        TokenType.FIRST,
 501        TokenType.FORMAT,
 502        TokenType.GLOB,
 503        TokenType.IDENTIFIER,
 504        TokenType.INDEX,
 505        TokenType.ISNULL,
 506        TokenType.ILIKE,
 507        TokenType.INSERT,
 508        TokenType.LIKE,
 509        TokenType.MERGE,
 510        TokenType.OFFSET,
 511        TokenType.PRIMARY_KEY,
 512        TokenType.RANGE,
 513        TokenType.REPLACE,
 514        TokenType.RLIKE,
 515        TokenType.ROW,
 516        TokenType.UNNEST,
 517        TokenType.VAR,
 518        TokenType.LEFT,
 519        TokenType.RIGHT,
 520        TokenType.SEQUENCE,
 521        TokenType.DATE,
 522        TokenType.DATETIME,
 523        TokenType.TABLE,
 524        TokenType.TIMESTAMP,
 525        TokenType.TIMESTAMPTZ,
 526        TokenType.TRUNCATE,
 527        TokenType.WINDOW,
 528        TokenType.XOR,
 529        *TYPE_TOKENS,
 530        *SUBQUERY_PREDICATES,
 531    }
 532
 533    CONJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
 534        TokenType.AND: exp.And,
 535    }
 536
 537    ASSIGNMENT: t.Dict[TokenType, t.Type[exp.Expression]] = {
 538        TokenType.COLON_EQ: exp.PropertyEQ,
 539    }
 540
 541    DISJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
 542        TokenType.OR: exp.Or,
 543    }
 544
 545    EQUALITY = {
 546        TokenType.EQ: exp.EQ,
 547        TokenType.NEQ: exp.NEQ,
 548        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
 549    }
 550
 551    COMPARISON = {
 552        TokenType.GT: exp.GT,
 553        TokenType.GTE: exp.GTE,
 554        TokenType.LT: exp.LT,
 555        TokenType.LTE: exp.LTE,
 556    }
 557
 558    BITWISE = {
 559        TokenType.AMP: exp.BitwiseAnd,
 560        TokenType.CARET: exp.BitwiseXor,
 561        TokenType.PIPE: exp.BitwiseOr,
 562    }
 563
 564    TERM = {
 565        TokenType.DASH: exp.Sub,
 566        TokenType.PLUS: exp.Add,
 567        TokenType.MOD: exp.Mod,
 568        TokenType.COLLATE: exp.Collate,
 569    }
 570
 571    FACTOR = {
 572        TokenType.DIV: exp.IntDiv,
 573        TokenType.LR_ARROW: exp.Distance,
 574        TokenType.SLASH: exp.Div,
 575        TokenType.STAR: exp.Mul,
 576    }
 577
 578    EXPONENT: t.Dict[TokenType, t.Type[exp.Expression]] = {}
 579
 580    TIMES = {
 581        TokenType.TIME,
 582        TokenType.TIMETZ,
 583    }
 584
 585    TIMESTAMPS = {
 586        TokenType.TIMESTAMP,
 587        TokenType.TIMESTAMPTZ,
 588        TokenType.TIMESTAMPLTZ,
 589        *TIMES,
 590    }
 591
 592    SET_OPERATIONS = {
 593        TokenType.UNION,
 594        TokenType.INTERSECT,
 595        TokenType.EXCEPT,
 596    }
 597
 598    JOIN_METHODS = {
 599        TokenType.ASOF,
 600        TokenType.NATURAL,
 601        TokenType.POSITIONAL,
 602    }
 603
 604    JOIN_SIDES = {
 605        TokenType.LEFT,
 606        TokenType.RIGHT,
 607        TokenType.FULL,
 608    }
 609
 610    JOIN_KINDS = {
 611        TokenType.ANTI,
 612        TokenType.CROSS,
 613        TokenType.INNER,
 614        TokenType.OUTER,
 615        TokenType.SEMI,
 616        TokenType.STRAIGHT_JOIN,
 617    }
 618
 619    JOIN_HINTS: t.Set[str] = set()
 620
 621    LAMBDAS = {
 622        TokenType.ARROW: lambda self, expressions: self.expression(
 623            exp.Lambda,
 624            this=self._replace_lambda(
 625                self._parse_assignment(),
 626                expressions,
 627            ),
 628            expressions=expressions,
 629        ),
 630        TokenType.FARROW: lambda self, expressions: self.expression(
 631            exp.Kwarg,
 632            this=exp.var(expressions[0].name),
 633            expression=self._parse_assignment(),
 634        ),
 635    }
 636
 637    COLUMN_OPERATORS = {
 638        TokenType.DOT: None,
 639        TokenType.DCOLON: lambda self, this, to: self.expression(
 640            exp.Cast if self.STRICT_CAST else exp.TryCast,
 641            this=this,
 642            to=to,
 643        ),
 644        TokenType.ARROW: lambda self, this, path: self.expression(
 645            exp.JSONExtract,
 646            this=this,
 647            expression=self.dialect.to_json_path(path),
 648            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
 649        ),
 650        TokenType.DARROW: lambda self, this, path: self.expression(
 651            exp.JSONExtractScalar,
 652            this=this,
 653            expression=self.dialect.to_json_path(path),
 654            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
 655        ),
 656        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
 657            exp.JSONBExtract,
 658            this=this,
 659            expression=path,
 660        ),
 661        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
 662            exp.JSONBExtractScalar,
 663            this=this,
 664            expression=path,
 665        ),
 666        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
 667            exp.JSONBContains,
 668            this=this,
 669            expression=key,
 670        ),
 671    }
 672
 673    EXPRESSION_PARSERS = {
 674        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
 675        exp.Column: lambda self: self._parse_column(),
 676        exp.Condition: lambda self: self._parse_assignment(),
 677        exp.DataType: lambda self: self._parse_types(allow_identifiers=False, schema=True),
 678        exp.Expression: lambda self: self._parse_expression(),
 679        exp.From: lambda self: self._parse_from(joins=True),
 680        exp.Group: lambda self: self._parse_group(),
 681        exp.Having: lambda self: self._parse_having(),
 682        exp.Identifier: lambda self: self._parse_id_var(),
 683        exp.Join: lambda self: self._parse_join(),
 684        exp.Lambda: lambda self: self._parse_lambda(),
 685        exp.Lateral: lambda self: self._parse_lateral(),
 686        exp.Limit: lambda self: self._parse_limit(),
 687        exp.Offset: lambda self: self._parse_offset(),
 688        exp.Order: lambda self: self._parse_order(),
 689        exp.Ordered: lambda self: self._parse_ordered(),
 690        exp.Properties: lambda self: self._parse_properties(),
 691        exp.Qualify: lambda self: self._parse_qualify(),
 692        exp.Returning: lambda self: self._parse_returning(),
 693        exp.Select: lambda self: self._parse_select(),
 694        exp.Sort: lambda self: self._parse_sort(exp.Sort, TokenType.SORT_BY),
 695        exp.Table: lambda self: self._parse_table_parts(),
 696        exp.TableAlias: lambda self: self._parse_table_alias(),
 697        exp.When: lambda self: seq_get(self._parse_when_matched(), 0),
 698        exp.Where: lambda self: self._parse_where(),
 699        exp.Window: lambda self: self._parse_named_window(),
 700        exp.With: lambda self: self._parse_with(),
 701        "JOIN_TYPE": lambda self: self._parse_join_parts(),
 702    }
 703
 704    STATEMENT_PARSERS = {
 705        TokenType.ALTER: lambda self: self._parse_alter(),
 706        TokenType.BEGIN: lambda self: self._parse_transaction(),
 707        TokenType.CACHE: lambda self: self._parse_cache(),
 708        TokenType.COMMENT: lambda self: self._parse_comment(),
 709        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
 710        TokenType.COPY: lambda self: self._parse_copy(),
 711        TokenType.CREATE: lambda self: self._parse_create(),
 712        TokenType.DELETE: lambda self: self._parse_delete(),
 713        TokenType.DESC: lambda self: self._parse_describe(),
 714        TokenType.DESCRIBE: lambda self: self._parse_describe(),
 715        TokenType.DROP: lambda self: self._parse_drop(),
 716        TokenType.INSERT: lambda self: self._parse_insert(),
 717        TokenType.KILL: lambda self: self._parse_kill(),
 718        TokenType.LOAD: lambda self: self._parse_load(),
 719        TokenType.MERGE: lambda self: self._parse_merge(),
 720        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
 721        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
 722        TokenType.REFRESH: lambda self: self._parse_refresh(),
 723        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
 724        TokenType.SET: lambda self: self._parse_set(),
 725        TokenType.TRUNCATE: lambda self: self._parse_truncate_table(),
 726        TokenType.UNCACHE: lambda self: self._parse_uncache(),
 727        TokenType.UPDATE: lambda self: self._parse_update(),
 728        TokenType.USE: lambda self: self.expression(
 729            exp.Use,
 730            kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
 731            this=self._parse_table(schema=False),
 732        ),
 733        TokenType.SEMICOLON: lambda self: self.expression(exp.Semicolon),
 734    }
 735
 736    UNARY_PARSERS = {
 737        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
 738        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
 739        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
 740        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
 741        TokenType.PIPE_SLASH: lambda self: self.expression(exp.Sqrt, this=self._parse_unary()),
 742        TokenType.DPIPE_SLASH: lambda self: self.expression(exp.Cbrt, this=self._parse_unary()),
 743    }
 744
 745    STRING_PARSERS = {
 746        TokenType.HEREDOC_STRING: lambda self, token: self.expression(
 747            exp.RawString, this=token.text
 748        ),
 749        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
 750            exp.National, this=token.text
 751        ),
 752        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
 753        TokenType.STRING: lambda self, token: self.expression(
 754            exp.Literal, this=token.text, is_string=True
 755        ),
 756        TokenType.UNICODE_STRING: lambda self, token: self.expression(
 757            exp.UnicodeString,
 758            this=token.text,
 759            escape=self._match_text_seq("UESCAPE") and self._parse_string(),
 760        ),
 761    }
 762
 763    NUMERIC_PARSERS = {
 764        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
 765        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
 766        TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text),
 767        TokenType.NUMBER: lambda self, token: self.expression(
 768            exp.Literal, this=token.text, is_string=False
 769        ),
 770    }
 771
 772    PRIMARY_PARSERS = {
 773        **STRING_PARSERS,
 774        **NUMERIC_PARSERS,
 775        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
 776        TokenType.NULL: lambda self, _: self.expression(exp.Null),
 777        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
 778        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
 779        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
 780        TokenType.STAR: lambda self, _: self.expression(
 781            exp.Star,
 782            **{
 783                "except": self._parse_star_op("EXCEPT", "EXCLUDE"),
 784                "replace": self._parse_star_op("REPLACE"),
 785                "rename": self._parse_star_op("RENAME"),
 786            },
 787        ),
 788    }
 789
 790    PLACEHOLDER_PARSERS = {
 791        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
 792        TokenType.PARAMETER: lambda self: self._parse_parameter(),
 793        TokenType.COLON: lambda self: (
 794            self.expression(exp.Placeholder, this=self._prev.text)
 795            if self._match_set(self.ID_VAR_TOKENS)
 796            else None
 797        ),
 798    }
 799
 800    RANGE_PARSERS = {
 801        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
 802        TokenType.GLOB: binary_range_parser(exp.Glob),
 803        TokenType.ILIKE: binary_range_parser(exp.ILike),
 804        TokenType.IN: lambda self, this: self._parse_in(this),
 805        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
 806        TokenType.IS: lambda self, this: self._parse_is(this),
 807        TokenType.LIKE: binary_range_parser(exp.Like),
 808        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
 809        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
 810        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
 811        TokenType.FOR: lambda self, this: self._parse_comprehension(this),
 812    }
 813
 814    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
 815        "ALLOWED_VALUES": lambda self: self.expression(
 816            exp.AllowedValuesProperty, expressions=self._parse_csv(self._parse_primary)
 817        ),
 818        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
 819        "AUTO": lambda self: self._parse_auto_property(),
 820        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
 821        "BACKUP": lambda self: self.expression(
 822            exp.BackupProperty, this=self._parse_var(any_token=True)
 823        ),
 824        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
 825        "CHARSET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 826        "CHARACTER SET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 827        "CHECKSUM": lambda self: self._parse_checksum(),
 828        "CLUSTER BY": lambda self: self._parse_cluster(),
 829        "CLUSTERED": lambda self: self._parse_clustered_by(),
 830        "COLLATE": lambda self, **kwargs: self._parse_property_assignment(
 831            exp.CollateProperty, **kwargs
 832        ),
 833        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
 834        "CONTAINS": lambda self: self._parse_contains_property(),
 835        "COPY": lambda self: self._parse_copy_property(),
 836        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
 837        "DATA_DELETION": lambda self: self._parse_data_deletion_property(),
 838        "DEFINER": lambda self: self._parse_definer(),
 839        "DETERMINISTIC": lambda self: self.expression(
 840            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 841        ),
 842        "DYNAMIC": lambda self: self.expression(exp.DynamicProperty),
 843        "DISTKEY": lambda self: self._parse_distkey(),
 844        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
 845        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
 846        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
 847        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
 848        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
 849        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 850        "FREESPACE": lambda self: self._parse_freespace(),
 851        "GLOBAL": lambda self: self.expression(exp.GlobalProperty),
 852        "HEAP": lambda self: self.expression(exp.HeapProperty),
 853        "ICEBERG": lambda self: self.expression(exp.IcebergProperty),
 854        "IMMUTABLE": lambda self: self.expression(
 855            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 856        ),
 857        "INHERITS": lambda self: self.expression(
 858            exp.InheritsProperty, expressions=self._parse_wrapped_csv(self._parse_table)
 859        ),
 860        "INPUT": lambda self: self.expression(exp.InputModelProperty, this=self._parse_schema()),
 861        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
 862        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
 863        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
 864        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
 865        "LIKE": lambda self: self._parse_create_like(),
 866        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
 867        "LOCK": lambda self: self._parse_locking(),
 868        "LOCKING": lambda self: self._parse_locking(),
 869        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
 870        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
 871        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
 872        "MODIFIES": lambda self: self._parse_modifies_property(),
 873        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
 874        "NO": lambda self: self._parse_no_property(),
 875        "ON": lambda self: self._parse_on_property(),
 876        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
 877        "OUTPUT": lambda self: self.expression(exp.OutputModelProperty, this=self._parse_schema()),
 878        "PARTITION": lambda self: self._parse_partitioned_of(),
 879        "PARTITION BY": lambda self: self._parse_partitioned_by(),
 880        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
 881        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
 882        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
 883        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
 884        "READS": lambda self: self._parse_reads_property(),
 885        "REMOTE": lambda self: self._parse_remote_with_connection(),
 886        "RETURNS": lambda self: self._parse_returns(),
 887        "STRICT": lambda self: self.expression(exp.StrictProperty),
 888        "ROW": lambda self: self._parse_row(),
 889        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
 890        "SAMPLE": lambda self: self.expression(
 891            exp.SampleProperty, this=self._match_text_seq("BY") and self._parse_bitwise()
 892        ),
 893        "SECURE": lambda self: self.expression(exp.SecureProperty),
 894        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
 895        "SETTINGS": lambda self: self.expression(
 896            exp.SettingsProperty, expressions=self._parse_csv(self._parse_set_item)
 897        ),
 898        "SHARING": lambda self: self._parse_property_assignment(exp.SharingProperty),
 899        "SORTKEY": lambda self: self._parse_sortkey(),
 900        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
 901        "STABLE": lambda self: self.expression(
 902            exp.StabilityProperty, this=exp.Literal.string("STABLE")
 903        ),
 904        "STORED": lambda self: self._parse_stored(),
 905        "SYSTEM_VERSIONING": lambda self: self._parse_system_versioning_property(),
 906        "TBLPROPERTIES": lambda self: self._parse_wrapped_properties(),
 907        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
 908        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
 909        "TO": lambda self: self._parse_to_table(),
 910        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
 911        "TRANSFORM": lambda self: self.expression(
 912            exp.TransformModelProperty, expressions=self._parse_wrapped_csv(self._parse_expression)
 913        ),
 914        "TTL": lambda self: self._parse_ttl(),
 915        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 916        "UNLOGGED": lambda self: self.expression(exp.UnloggedProperty),
 917        "VOLATILE": lambda self: self._parse_volatile_property(),
 918        "WITH": lambda self: self._parse_with_property(),
 919    }
 920
 921    CONSTRAINT_PARSERS = {
 922        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
 923        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
 924        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
 925        "CHARACTER SET": lambda self: self.expression(
 926            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
 927        ),
 928        "CHECK": lambda self: self.expression(
 929            exp.CheckColumnConstraint,
 930            this=self._parse_wrapped(self._parse_assignment),
 931            enforced=self._match_text_seq("ENFORCED"),
 932        ),
 933        "COLLATE": lambda self: self.expression(
 934            exp.CollateColumnConstraint,
 935            this=self._parse_identifier() or self._parse_column(),
 936        ),
 937        "COMMENT": lambda self: self.expression(
 938            exp.CommentColumnConstraint, this=self._parse_string()
 939        ),
 940        "COMPRESS": lambda self: self._parse_compress(),
 941        "CLUSTERED": lambda self: self.expression(
 942            exp.ClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
 943        ),
 944        "NONCLUSTERED": lambda self: self.expression(
 945            exp.NonClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
 946        ),
 947        "DEFAULT": lambda self: self.expression(
 948            exp.DefaultColumnConstraint, this=self._parse_bitwise()
 949        ),
 950        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
 951        "EPHEMERAL": lambda self: self.expression(
 952            exp.EphemeralColumnConstraint, this=self._parse_bitwise()
 953        ),
 954        "EXCLUDE": lambda self: self.expression(
 955            exp.ExcludeColumnConstraint, this=self._parse_index_params()
 956        ),
 957        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
 958        "FORMAT": lambda self: self.expression(
 959            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
 960        ),
 961        "GENERATED": lambda self: self._parse_generated_as_identity(),
 962        "IDENTITY": lambda self: self._parse_auto_increment(),
 963        "INLINE": lambda self: self._parse_inline(),
 964        "LIKE": lambda self: self._parse_create_like(),
 965        "NOT": lambda self: self._parse_not_constraint(),
 966        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
 967        "ON": lambda self: (
 968            self._match(TokenType.UPDATE)
 969            and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function())
 970        )
 971        or self.expression(exp.OnProperty, this=self._parse_id_var()),
 972        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
 973        "PERIOD": lambda self: self._parse_period_for_system_time(),
 974        "PRIMARY KEY": lambda self: self._parse_primary_key(),
 975        "REFERENCES": lambda self: self._parse_references(match=False),
 976        "TITLE": lambda self: self.expression(
 977            exp.TitleColumnConstraint, this=self._parse_var_or_string()
 978        ),
 979        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
 980        "UNIQUE": lambda self: self._parse_unique(),
 981        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
 982        "WITH": lambda self: self.expression(
 983            exp.Properties, expressions=self._parse_wrapped_properties()
 984        ),
 985    }
 986
 987    ALTER_PARSERS = {
 988        "ADD": lambda self: self._parse_alter_table_add(),
 989        "ALTER": lambda self: self._parse_alter_table_alter(),
 990        "CLUSTER BY": lambda self: self._parse_cluster(wrapped=True),
 991        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
 992        "DROP": lambda self: self._parse_alter_table_drop(),
 993        "RENAME": lambda self: self._parse_alter_table_rename(),
 994        "SET": lambda self: self._parse_alter_table_set(),
 995    }
 996
 997    ALTER_ALTER_PARSERS = {
 998        "DISTKEY": lambda self: self._parse_alter_diststyle(),
 999        "DISTSTYLE": lambda self: self._parse_alter_diststyle(),
1000        "SORTKEY": lambda self: self._parse_alter_sortkey(),
1001        "COMPOUND": lambda self: self._parse_alter_sortkey(compound=True),
1002    }
1003
1004    SCHEMA_UNNAMED_CONSTRAINTS = {
1005        "CHECK",
1006        "EXCLUDE",
1007        "FOREIGN KEY",
1008        "LIKE",
1009        "PERIOD",
1010        "PRIMARY KEY",
1011        "UNIQUE",
1012    }
1013
1014    NO_PAREN_FUNCTION_PARSERS = {
1015        "ANY": lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
1016        "CASE": lambda self: self._parse_case(),
1017        "CONNECT_BY_ROOT": lambda self: self.expression(
1018            exp.ConnectByRoot, this=self._parse_column()
1019        ),
1020        "IF": lambda self: self._parse_if(),
1021        "NEXT": lambda self: self._parse_next_value_for(),
1022    }
1023
1024    INVALID_FUNC_NAME_TOKENS = {
1025        TokenType.IDENTIFIER,
1026        TokenType.STRING,
1027    }
1028
1029    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
1030
1031    KEY_VALUE_DEFINITIONS = (exp.Alias, exp.EQ, exp.PropertyEQ, exp.Slice)
1032
1033    FUNCTION_PARSERS = {
1034        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
1035        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
1036        "DECODE": lambda self: self._parse_decode(),
1037        "EXTRACT": lambda self: self._parse_extract(),
1038        "GAP_FILL": lambda self: self._parse_gap_fill(),
1039        "JSON_OBJECT": lambda self: self._parse_json_object(),
1040        "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
1041        "JSON_TABLE": lambda self: self._parse_json_table(),
1042        "MATCH": lambda self: self._parse_match_against(),
1043        "OPENJSON": lambda self: self._parse_open_json(),
1044        "POSITION": lambda self: self._parse_position(),
1045        "PREDICT": lambda self: self._parse_predict(),
1046        "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
1047        "STRING_AGG": lambda self: self._parse_string_agg(),
1048        "SUBSTRING": lambda self: self._parse_substring(),
1049        "TRIM": lambda self: self._parse_trim(),
1050        "TRY_CAST": lambda self: self._parse_cast(False, safe=True),
1051        "TRY_CONVERT": lambda self: self._parse_convert(False, safe=True),
1052    }
1053
1054    QUERY_MODIFIER_PARSERS = {
1055        TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
1056        TokenType.PREWHERE: lambda self: ("prewhere", self._parse_prewhere()),
1057        TokenType.WHERE: lambda self: ("where", self._parse_where()),
1058        TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
1059        TokenType.HAVING: lambda self: ("having", self._parse_having()),
1060        TokenType.QUALIFY: lambda self: ("qualify", self._parse_qualify()),
1061        TokenType.WINDOW: lambda self: ("windows", self._parse_window_clause()),
1062        TokenType.ORDER_BY: lambda self: ("order", self._parse_order()),
1063        TokenType.LIMIT: lambda self: ("limit", self._parse_limit()),
1064        TokenType.FETCH: lambda self: ("limit", self._parse_limit()),
1065        TokenType.OFFSET: lambda self: ("offset", self._parse_offset()),
1066        TokenType.FOR: lambda self: ("locks", self._parse_locks()),
1067        TokenType.LOCK: lambda self: ("locks", self._parse_locks()),
1068        TokenType.TABLE_SAMPLE: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
1069        TokenType.USING: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
1070        TokenType.CLUSTER_BY: lambda self: (
1071            "cluster",
1072            self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
1073        ),
1074        TokenType.DISTRIBUTE_BY: lambda self: (
1075            "distribute",
1076            self._parse_sort(exp.Distribute, TokenType.DISTRIBUTE_BY),
1077        ),
1078        TokenType.SORT_BY: lambda self: ("sort", self._parse_sort(exp.Sort, TokenType.SORT_BY)),
1079        TokenType.CONNECT_BY: lambda self: ("connect", self._parse_connect(skip_start_token=True)),
1080        TokenType.START_WITH: lambda self: ("connect", self._parse_connect()),
1081    }
1082
1083    SET_PARSERS = {
1084        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
1085        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
1086        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
1087        "TRANSACTION": lambda self: self._parse_set_transaction(),
1088    }
1089
1090    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
1091
1092    TYPE_LITERAL_PARSERS = {
1093        exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
1094    }
1095
1096    TYPE_CONVERTERS: t.Dict[exp.DataType.Type, t.Callable[[exp.DataType], exp.DataType]] = {}
1097
1098    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
1099
1100    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
1101
1102    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
1103    TRANSACTION_CHARACTERISTICS: OPTIONS_TYPE = {
1104        "ISOLATION": (
1105            ("LEVEL", "REPEATABLE", "READ"),
1106            ("LEVEL", "READ", "COMMITTED"),
1107            ("LEVEL", "READ", "UNCOMITTED"),
1108            ("LEVEL", "SERIALIZABLE"),
1109        ),
1110        "READ": ("WRITE", "ONLY"),
1111    }
1112
1113    CONFLICT_ACTIONS: OPTIONS_TYPE = dict.fromkeys(
1114        ("ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK", "UPDATE"), tuple()
1115    )
1116    CONFLICT_ACTIONS["DO"] = ("NOTHING", "UPDATE")
1117
1118    CREATE_SEQUENCE: OPTIONS_TYPE = {
1119        "SCALE": ("EXTEND", "NOEXTEND"),
1120        "SHARD": ("EXTEND", "NOEXTEND"),
1121        "NO": ("CYCLE", "CACHE", "MAXVALUE", "MINVALUE"),
1122        **dict.fromkeys(
1123            (
1124                "SESSION",
1125                "GLOBAL",
1126                "KEEP",
1127                "NOKEEP",
1128                "ORDER",
1129                "NOORDER",
1130                "NOCACHE",
1131                "CYCLE",
1132                "NOCYCLE",
1133                "NOMINVALUE",
1134                "NOMAXVALUE",
1135                "NOSCALE",
1136                "NOSHARD",
1137            ),
1138            tuple(),
1139        ),
1140    }
1141
1142    ISOLATED_LOADING_OPTIONS: OPTIONS_TYPE = {"FOR": ("ALL", "INSERT", "NONE")}
1143
1144    USABLES: OPTIONS_TYPE = dict.fromkeys(
1145        ("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA", "CATALOG"), tuple()
1146    )
1147
1148    CAST_ACTIONS: OPTIONS_TYPE = dict.fromkeys(("RENAME", "ADD"), ("FIELDS",))
1149
1150    SCHEMA_BINDING_OPTIONS: OPTIONS_TYPE = {
1151        "TYPE": ("EVOLUTION",),
1152        **dict.fromkeys(("BINDING", "COMPENSATION", "EVOLUTION"), tuple()),
1153    }
1154
1155    KEY_CONSTRAINT_OPTIONS: OPTIONS_TYPE = {
1156        "NOT": ("ENFORCED",),
1157        "MATCH": (
1158            "FULL",
1159            "PARTIAL",
1160            "SIMPLE",
1161        ),
1162        "INITIALLY": ("DEFERRED", "IMMEDIATE"),
1163        **dict.fromkeys(("DEFERRABLE", "NORELY"), tuple()),
1164    }
1165
1166    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
1167
1168    CLONE_KEYWORDS = {"CLONE", "COPY"}
1169    HISTORICAL_DATA_PREFIX = {"AT", "BEFORE", "END"}
1170    HISTORICAL_DATA_KIND = {"TIMESTAMP", "OFFSET", "STATEMENT", "STREAM"}
1171
1172    OPCLASS_FOLLOW_KEYWORDS = {"ASC", "DESC", "NULLS", "WITH"}
1173
1174    OPTYPE_FOLLOW_TOKENS = {TokenType.COMMA, TokenType.R_PAREN}
1175
1176    TABLE_INDEX_HINT_TOKENS = {TokenType.FORCE, TokenType.IGNORE, TokenType.USE}
1177
1178    VIEW_ATTRIBUTES = {"ENCRYPTION", "SCHEMABINDING", "VIEW_METADATA"}
1179
1180    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
1181    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
1182    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
1183
1184    JSON_KEY_VALUE_SEPARATOR_TOKENS = {TokenType.COLON, TokenType.COMMA, TokenType.IS}
1185
1186    FETCH_TOKENS = ID_VAR_TOKENS - {TokenType.ROW, TokenType.ROWS, TokenType.PERCENT}
1187
1188    ADD_CONSTRAINT_TOKENS = {
1189        TokenType.CONSTRAINT,
1190        TokenType.FOREIGN_KEY,
1191        TokenType.INDEX,
1192        TokenType.KEY,
1193        TokenType.PRIMARY_KEY,
1194        TokenType.UNIQUE,
1195    }
1196
1197    DISTINCT_TOKENS = {TokenType.DISTINCT}
1198
1199    NULL_TOKENS = {TokenType.NULL}
1200
1201    UNNEST_OFFSET_ALIAS_TOKENS = ID_VAR_TOKENS - SET_OPERATIONS
1202
1203    SELECT_START_TOKENS = {TokenType.L_PAREN, TokenType.WITH, TokenType.SELECT}
1204
1205    COPY_INTO_VARLEN_OPTIONS = {"FILE_FORMAT", "COPY_OPTIONS", "FORMAT_OPTIONS", "CREDENTIAL"}
1206
1207    STRICT_CAST = True
1208
1209    PREFIXED_PIVOT_COLUMNS = False
1210    IDENTIFY_PIVOT_STRINGS = False
1211
1212    LOG_DEFAULTS_TO_LN = False
1213
1214    # Whether ADD is present for each column added by ALTER TABLE
1215    ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
1216
1217    # Whether the table sample clause expects CSV syntax
1218    TABLESAMPLE_CSV = False
1219
1220    # The default method used for table sampling
1221    DEFAULT_SAMPLING_METHOD: t.Optional[str] = None
1222
1223    # Whether the SET command needs a delimiter (e.g. "=") for assignments
1224    SET_REQUIRES_ASSIGNMENT_DELIMITER = True
1225
1226    # Whether the TRIM function expects the characters to trim as its first argument
1227    TRIM_PATTERN_FIRST = False
1228
1229    # Whether string aliases are supported `SELECT COUNT(*) 'count'`
1230    STRING_ALIASES = False
1231
1232    # Whether query modifiers such as LIMIT are attached to the UNION node (vs its right operand)
1233    MODIFIERS_ATTACHED_TO_SET_OP = True
1234    SET_OP_MODIFIERS = {"order", "limit", "offset"}
1235
1236    # Whether to parse IF statements that aren't followed by a left parenthesis as commands
1237    NO_PAREN_IF_COMMANDS = True
1238
1239    # Whether the -> and ->> operators expect documents of type JSON (e.g. Postgres)
1240    JSON_ARROWS_REQUIRE_JSON_TYPE = False
1241
1242    # Whether the `:` operator is used to extract a value from a VARIANT column
1243    COLON_IS_VARIANT_EXTRACT = False
1244
1245    # Whether or not a VALUES keyword needs to be followed by '(' to form a VALUES clause.
1246    # If this is True and '(' is not found, the keyword will be treated as an identifier
1247    VALUES_FOLLOWED_BY_PAREN = True
1248
1249    # Whether implicit unnesting is supported, e.g. SELECT 1 FROM y.z AS z, z.a (Redshift)
1250    SUPPORTS_IMPLICIT_UNNEST = False
1251
1252    # Whether or not interval spans are supported, INTERVAL 1 YEAR TO MONTHS
1253    INTERVAL_SPANS = True
1254
1255    # Whether a PARTITION clause can follow a table reference
1256    SUPPORTS_PARTITION_SELECTION = False
1257
1258    __slots__ = (
1259        "error_level",
1260        "error_message_context",
1261        "max_errors",
1262        "dialect",
1263        "sql",
1264        "errors",
1265        "_tokens",
1266        "_index",
1267        "_curr",
1268        "_next",
1269        "_prev",
1270        "_prev_comments",
1271    )
1272
1273    # Autofilled
1274    SHOW_TRIE: t.Dict = {}
1275    SET_TRIE: t.Dict = {}
1276
1277    def __init__(
1278        self,
1279        error_level: t.Optional[ErrorLevel] = None,
1280        error_message_context: int = 100,
1281        max_errors: int = 3,
1282        dialect: DialectType = None,
1283    ):
1284        from sqlglot.dialects import Dialect
1285
1286        self.error_level = error_level or ErrorLevel.IMMEDIATE
1287        self.error_message_context = error_message_context
1288        self.max_errors = max_errors
1289        self.dialect = Dialect.get_or_raise(dialect)
1290        self.reset()
1291
1292    def reset(self):
1293        self.sql = ""
1294        self.errors = []
1295        self._tokens = []
1296        self._index = 0
1297        self._curr = None
1298        self._next = None
1299        self._prev = None
1300        self._prev_comments = None
1301
1302    def parse(
1303        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1304    ) -> t.List[t.Optional[exp.Expression]]:
1305        """
1306        Parses a list of tokens and returns a list of syntax trees, one tree
1307        per parsed SQL statement.
1308
1309        Args:
1310            raw_tokens: The list of tokens.
1311            sql: The original SQL string, used to produce helpful debug messages.
1312
1313        Returns:
1314            The list of the produced syntax trees.
1315        """
1316        return self._parse(
1317            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1318        )
1319
1320    def parse_into(
1321        self,
1322        expression_types: exp.IntoType,
1323        raw_tokens: t.List[Token],
1324        sql: t.Optional[str] = None,
1325    ) -> t.List[t.Optional[exp.Expression]]:
1326        """
1327        Parses a list of tokens into a given Expression type. If a collection of Expression
1328        types is given instead, this method will try to parse the token list into each one
1329        of them, stopping at the first for which the parsing succeeds.
1330
1331        Args:
1332            expression_types: The expression type(s) to try and parse the token list into.
1333            raw_tokens: The list of tokens.
1334            sql: The original SQL string, used to produce helpful debug messages.
1335
1336        Returns:
1337            The target Expression.
1338        """
1339        errors = []
1340        for expression_type in ensure_list(expression_types):
1341            parser = self.EXPRESSION_PARSERS.get(expression_type)
1342            if not parser:
1343                raise TypeError(f"No parser registered for {expression_type}")
1344
1345            try:
1346                return self._parse(parser, raw_tokens, sql)
1347            except ParseError as e:
1348                e.errors[0]["into_expression"] = expression_type
1349                errors.append(e)
1350
1351        raise ParseError(
1352            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1353            errors=merge_errors(errors),
1354        ) from errors[-1]
1355
1356    def _parse(
1357        self,
1358        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
1359        raw_tokens: t.List[Token],
1360        sql: t.Optional[str] = None,
1361    ) -> t.List[t.Optional[exp.Expression]]:
1362        self.reset()
1363        self.sql = sql or ""
1364
1365        total = len(raw_tokens)
1366        chunks: t.List[t.List[Token]] = [[]]
1367
1368        for i, token in enumerate(raw_tokens):
1369            if token.token_type == TokenType.SEMICOLON:
1370                if token.comments:
1371                    chunks.append([token])
1372
1373                if i < total - 1:
1374                    chunks.append([])
1375            else:
1376                chunks[-1].append(token)
1377
1378        expressions = []
1379
1380        for tokens in chunks:
1381            self._index = -1
1382            self._tokens = tokens
1383            self._advance()
1384
1385            expressions.append(parse_method(self))
1386
1387            if self._index < len(self._tokens):
1388                self.raise_error("Invalid expression / Unexpected token")
1389
1390            self.check_errors()
1391
1392        return expressions
1393
1394    def check_errors(self) -> None:
1395        """Logs or raises any found errors, depending on the chosen error level setting."""
1396        if self.error_level == ErrorLevel.WARN:
1397            for error in self.errors:
1398                logger.error(str(error))
1399        elif self.error_level == ErrorLevel.RAISE and self.errors:
1400            raise ParseError(
1401                concat_messages(self.errors, self.max_errors),
1402                errors=merge_errors(self.errors),
1403            )
1404
1405    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1406        """
1407        Appends an error in the list of recorded errors or raises it, depending on the chosen
1408        error level setting.
1409        """
1410        token = token or self._curr or self._prev or Token.string("")
1411        start = token.start
1412        end = token.end + 1
1413        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1414        highlight = self.sql[start:end]
1415        end_context = self.sql[end : end + self.error_message_context]
1416
1417        error = ParseError.new(
1418            f"{message}. Line {token.line}, Col: {token.col}.\n"
1419            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1420            description=message,
1421            line=token.line,
1422            col=token.col,
1423            start_context=start_context,
1424            highlight=highlight,
1425            end_context=end_context,
1426        )
1427
1428        if self.error_level == ErrorLevel.IMMEDIATE:
1429            raise error
1430
1431        self.errors.append(error)
1432
1433    def expression(
1434        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1435    ) -> E:
1436        """
1437        Creates a new, validated Expression.
1438
1439        Args:
1440            exp_class: The expression class to instantiate.
1441            comments: An optional list of comments to attach to the expression.
1442            kwargs: The arguments to set for the expression along with their respective values.
1443
1444        Returns:
1445            The target expression.
1446        """
1447        instance = exp_class(**kwargs)
1448        instance.add_comments(comments) if comments else self._add_comments(instance)
1449        return self.validate_expression(instance)
1450
1451    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
1452        if expression and self._prev_comments:
1453            expression.add_comments(self._prev_comments)
1454            self._prev_comments = None
1455
1456    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1457        """
1458        Validates an Expression, making sure that all its mandatory arguments are set.
1459
1460        Args:
1461            expression: The expression to validate.
1462            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1463
1464        Returns:
1465            The validated expression.
1466        """
1467        if self.error_level != ErrorLevel.IGNORE:
1468            for error_message in expression.error_messages(args):
1469                self.raise_error(error_message)
1470
1471        return expression
1472
1473    def _find_sql(self, start: Token, end: Token) -> str:
1474        return self.sql[start.start : end.end + 1]
1475
1476    def _is_connected(self) -> bool:
1477        return self._prev and self._curr and self._prev.end + 1 == self._curr.start
1478
1479    def _advance(self, times: int = 1) -> None:
1480        self._index += times
1481        self._curr = seq_get(self._tokens, self._index)
1482        self._next = seq_get(self._tokens, self._index + 1)
1483
1484        if self._index > 0:
1485            self._prev = self._tokens[self._index - 1]
1486            self._prev_comments = self._prev.comments
1487        else:
1488            self._prev = None
1489            self._prev_comments = None
1490
1491    def _retreat(self, index: int) -> None:
1492        if index != self._index:
1493            self._advance(index - self._index)
1494
1495    def _warn_unsupported(self) -> None:
1496        if len(self._tokens) <= 1:
1497            return
1498
1499        # We use _find_sql because self.sql may comprise multiple chunks, and we're only
1500        # interested in emitting a warning for the one being currently processed.
1501        sql = self._find_sql(self._tokens[0], self._tokens[-1])[: self.error_message_context]
1502
1503        logger.warning(
1504            f"'{sql}' contains unsupported syntax. Falling back to parsing as a 'Command'."
1505        )
1506
1507    def _parse_command(self) -> exp.Command:
1508        self._warn_unsupported()
1509        return self.expression(
1510            exp.Command,
1511            comments=self._prev_comments,
1512            this=self._prev.text.upper(),
1513            expression=self._parse_string(),
1514        )
1515
1516    def _try_parse(self, parse_method: t.Callable[[], T], retreat: bool = False) -> t.Optional[T]:
1517        """
1518        Attemps to backtrack if a parse function that contains a try/catch internally raises an error.
1519        This behavior can be different depending on the uset-set ErrorLevel, so _try_parse aims to
1520        solve this by setting & resetting the parser state accordingly
1521        """
1522        index = self._index
1523        error_level = self.error_level
1524
1525        self.error_level = ErrorLevel.IMMEDIATE
1526        try:
1527            this = parse_method()
1528        except ParseError:
1529            this = None
1530        finally:
1531            if not this or retreat:
1532                self._retreat(index)
1533            self.error_level = error_level
1534
1535        return this
1536
1537    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
1538        start = self._prev
1539        exists = self._parse_exists() if allow_exists else None
1540
1541        self._match(TokenType.ON)
1542
1543        materialized = self._match_text_seq("MATERIALIZED")
1544        kind = self._match_set(self.CREATABLES) and self._prev
1545        if not kind:
1546            return self._parse_as_command(start)
1547
1548        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1549            this = self._parse_user_defined_function(kind=kind.token_type)
1550        elif kind.token_type == TokenType.TABLE:
1551            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
1552        elif kind.token_type == TokenType.COLUMN:
1553            this = self._parse_column()
1554        else:
1555            this = self._parse_id_var()
1556
1557        self._match(TokenType.IS)
1558
1559        return self.expression(
1560            exp.Comment,
1561            this=this,
1562            kind=kind.text,
1563            expression=self._parse_string(),
1564            exists=exists,
1565            materialized=materialized,
1566        )
1567
1568    def _parse_to_table(
1569        self,
1570    ) -> exp.ToTableProperty:
1571        table = self._parse_table_parts(schema=True)
1572        return self.expression(exp.ToTableProperty, this=table)
1573
1574    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
1575    def _parse_ttl(self) -> exp.Expression:
1576        def _parse_ttl_action() -> t.Optional[exp.Expression]:
1577            this = self._parse_bitwise()
1578
1579            if self._match_text_seq("DELETE"):
1580                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
1581            if self._match_text_seq("RECOMPRESS"):
1582                return self.expression(
1583                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
1584                )
1585            if self._match_text_seq("TO", "DISK"):
1586                return self.expression(
1587                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
1588                )
1589            if self._match_text_seq("TO", "VOLUME"):
1590                return self.expression(
1591                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
1592                )
1593
1594            return this
1595
1596        expressions = self._parse_csv(_parse_ttl_action)
1597        where = self._parse_where()
1598        group = self._parse_group()
1599
1600        aggregates = None
1601        if group and self._match(TokenType.SET):
1602            aggregates = self._parse_csv(self._parse_set_item)
1603
1604        return self.expression(
1605            exp.MergeTreeTTL,
1606            expressions=expressions,
1607            where=where,
1608            group=group,
1609            aggregates=aggregates,
1610        )
1611
1612    def _parse_statement(self) -> t.Optional[exp.Expression]:
1613        if self._curr is None:
1614            return None
1615
1616        if self._match_set(self.STATEMENT_PARSERS):
1617            return self.STATEMENT_PARSERS[self._prev.token_type](self)
1618
1619        if self._match_set(self.dialect.tokenizer.COMMANDS):
1620            return self._parse_command()
1621
1622        expression = self._parse_expression()
1623        expression = self._parse_set_operations(expression) if expression else self._parse_select()
1624        return self._parse_query_modifiers(expression)
1625
1626    def _parse_drop(self, exists: bool = False) -> exp.Drop | exp.Command:
1627        start = self._prev
1628        temporary = self._match(TokenType.TEMPORARY)
1629        materialized = self._match_text_seq("MATERIALIZED")
1630
1631        kind = self._match_set(self.CREATABLES) and self._prev.text
1632        if not kind:
1633            return self._parse_as_command(start)
1634
1635        if_exists = exists or self._parse_exists()
1636        table = self._parse_table_parts(
1637            schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
1638        )
1639
1640        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
1641
1642        if self._match(TokenType.L_PAREN, advance=False):
1643            expressions = self._parse_wrapped_csv(self._parse_types)
1644        else:
1645            expressions = None
1646
1647        return self.expression(
1648            exp.Drop,
1649            comments=start.comments,
1650            exists=if_exists,
1651            this=table,
1652            expressions=expressions,
1653            kind=kind.upper(),
1654            temporary=temporary,
1655            materialized=materialized,
1656            cascade=self._match_text_seq("CASCADE"),
1657            constraints=self._match_text_seq("CONSTRAINTS"),
1658            purge=self._match_text_seq("PURGE"),
1659            cluster=cluster,
1660        )
1661
1662    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
1663        return (
1664            self._match_text_seq("IF")
1665            and (not not_ or self._match(TokenType.NOT))
1666            and self._match(TokenType.EXISTS)
1667        )
1668
1669    def _parse_create(self) -> exp.Create | exp.Command:
1670        # Note: this can't be None because we've matched a statement parser
1671        start = self._prev
1672        comments = self._prev_comments
1673
1674        replace = (
1675            start.token_type == TokenType.REPLACE
1676            or self._match_pair(TokenType.OR, TokenType.REPLACE)
1677            or self._match_pair(TokenType.OR, TokenType.ALTER)
1678        )
1679
1680        unique = self._match(TokenType.UNIQUE)
1681
1682        if self._match_text_seq("CLUSTERED", "COLUMNSTORE"):
1683            clustered = True
1684        elif self._match_text_seq("NONCLUSTERED", "COLUMNSTORE") or self._match_text_seq(
1685            "COLUMNSTORE"
1686        ):
1687            clustered = False
1688        else:
1689            clustered = None
1690
1691        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
1692            self._advance()
1693
1694        properties = None
1695        create_token = self._match_set(self.CREATABLES) and self._prev
1696
1697        if not create_token:
1698            # exp.Properties.Location.POST_CREATE
1699            properties = self._parse_properties()
1700            create_token = self._match_set(self.CREATABLES) and self._prev
1701
1702            if not properties or not create_token:
1703                return self._parse_as_command(start)
1704
1705        concurrently = self._match_text_seq("CONCURRENTLY")
1706        exists = self._parse_exists(not_=True)
1707        this = None
1708        expression: t.Optional[exp.Expression] = None
1709        indexes = None
1710        no_schema_binding = None
1711        begin = None
1712        end = None
1713        clone = None
1714
1715        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
1716            nonlocal properties
1717            if properties and temp_props:
1718                properties.expressions.extend(temp_props.expressions)
1719            elif temp_props:
1720                properties = temp_props
1721
1722        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1723            this = self._parse_user_defined_function(kind=create_token.token_type)
1724
1725            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
1726            extend_props(self._parse_properties())
1727
1728            expression = self._match(TokenType.ALIAS) and self._parse_heredoc()
1729            extend_props(self._parse_properties())
1730
1731            if not expression:
1732                if self._match(TokenType.COMMAND):
1733                    expression = self._parse_as_command(self._prev)
1734                else:
1735                    begin = self._match(TokenType.BEGIN)
1736                    return_ = self._match_text_seq("RETURN")
1737
1738                    if self._match(TokenType.STRING, advance=False):
1739                        # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
1740                        # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
1741                        expression = self._parse_string()
1742                        extend_props(self._parse_properties())
1743                    else:
1744                        expression = self._parse_statement()
1745
1746                    end = self._match_text_seq("END")
1747
1748                    if return_:
1749                        expression = self.expression(exp.Return, this=expression)
1750        elif create_token.token_type == TokenType.INDEX:
1751            # Postgres allows anonymous indexes, eg. CREATE INDEX IF NOT EXISTS ON t(c)
1752            if not self._match(TokenType.ON):
1753                index = self._parse_id_var()
1754                anonymous = False
1755            else:
1756                index = None
1757                anonymous = True
1758
1759            this = self._parse_index(index=index, anonymous=anonymous)
1760        elif create_token.token_type in self.DB_CREATABLES:
1761            table_parts = self._parse_table_parts(
1762                schema=True, is_db_reference=create_token.token_type == TokenType.SCHEMA
1763            )
1764
1765            # exp.Properties.Location.POST_NAME
1766            self._match(TokenType.COMMA)
1767            extend_props(self._parse_properties(before=True))
1768
1769            this = self._parse_schema(this=table_parts)
1770
1771            # exp.Properties.Location.POST_SCHEMA and POST_WITH
1772            extend_props(self._parse_properties())
1773
1774            self._match(TokenType.ALIAS)
1775            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
1776                # exp.Properties.Location.POST_ALIAS
1777                extend_props(self._parse_properties())
1778
1779            if create_token.token_type == TokenType.SEQUENCE:
1780                expression = self._parse_types()
1781                extend_props(self._parse_properties())
1782            else:
1783                expression = self._parse_ddl_select()
1784
1785            if create_token.token_type == TokenType.TABLE:
1786                # exp.Properties.Location.POST_EXPRESSION
1787                extend_props(self._parse_properties())
1788
1789                indexes = []
1790                while True:
1791                    index = self._parse_index()
1792
1793                    # exp.Properties.Location.POST_INDEX
1794                    extend_props(self._parse_properties())
1795
1796                    if not index:
1797                        break
1798                    else:
1799                        self._match(TokenType.COMMA)
1800                        indexes.append(index)
1801            elif create_token.token_type == TokenType.VIEW:
1802                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
1803                    no_schema_binding = True
1804
1805            shallow = self._match_text_seq("SHALLOW")
1806
1807            if self._match_texts(self.CLONE_KEYWORDS):
1808                copy = self._prev.text.lower() == "copy"
1809                clone = self.expression(
1810                    exp.Clone, this=self._parse_table(schema=True), shallow=shallow, copy=copy
1811                )
1812
1813        if self._curr and not self._match_set((TokenType.R_PAREN, TokenType.COMMA), advance=False):
1814            return self._parse_as_command(start)
1815
1816        return self.expression(
1817            exp.Create,
1818            comments=comments,
1819            this=this,
1820            kind=create_token.text.upper(),
1821            replace=replace,
1822            unique=unique,
1823            expression=expression,
1824            exists=exists,
1825            properties=properties,
1826            indexes=indexes,
1827            no_schema_binding=no_schema_binding,
1828            begin=begin,
1829            end=end,
1830            clone=clone,
1831            concurrently=concurrently,
1832            clustered=clustered,
1833        )
1834
1835    def _parse_sequence_properties(self) -> t.Optional[exp.SequenceProperties]:
1836        seq = exp.SequenceProperties()
1837
1838        options = []
1839        index = self._index
1840
1841        while self._curr:
1842            self._match(TokenType.COMMA)
1843            if self._match_text_seq("INCREMENT"):
1844                self._match_text_seq("BY")
1845                self._match_text_seq("=")
1846                seq.set("increment", self._parse_term())
1847            elif self._match_text_seq("MINVALUE"):
1848                seq.set("minvalue", self._parse_term())
1849            elif self._match_text_seq("MAXVALUE"):
1850                seq.set("maxvalue", self._parse_term())
1851            elif self._match(TokenType.START_WITH) or self._match_text_seq("START"):
1852                self._match_text_seq("=")
1853                seq.set("start", self._parse_term())
1854            elif self._match_text_seq("CACHE"):
1855                # T-SQL allows empty CACHE which is initialized dynamically
1856                seq.set("cache", self._parse_number() or True)
1857            elif self._match_text_seq("OWNED", "BY"):
1858                # "OWNED BY NONE" is the default
1859                seq.set("owned", None if self._match_text_seq("NONE") else self._parse_column())
1860            else:
1861                opt = self._parse_var_from_options(self.CREATE_SEQUENCE, raise_unmatched=False)
1862                if opt:
1863                    options.append(opt)
1864                else:
1865                    break
1866
1867        seq.set("options", options if options else None)
1868        return None if self._index == index else seq
1869
1870    def _parse_property_before(self) -> t.Optional[exp.Expression]:
1871        # only used for teradata currently
1872        self._match(TokenType.COMMA)
1873
1874        kwargs = {
1875            "no": self._match_text_seq("NO"),
1876            "dual": self._match_text_seq("DUAL"),
1877            "before": self._match_text_seq("BEFORE"),
1878            "default": self._match_text_seq("DEFAULT"),
1879            "local": (self._match_text_seq("LOCAL") and "LOCAL")
1880            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
1881            "after": self._match_text_seq("AFTER"),
1882            "minimum": self._match_texts(("MIN", "MINIMUM")),
1883            "maximum": self._match_texts(("MAX", "MAXIMUM")),
1884        }
1885
1886        if self._match_texts(self.PROPERTY_PARSERS):
1887            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
1888            try:
1889                return parser(self, **{k: v for k, v in kwargs.items() if v})
1890            except TypeError:
1891                self.raise_error(f"Cannot parse property '{self._prev.text}'")
1892
1893        return None
1894
1895    def _parse_wrapped_properties(self) -> t.List[exp.Expression]:
1896        return self._parse_wrapped_csv(self._parse_property)
1897
1898    def _parse_property(self) -> t.Optional[exp.Expression]:
1899        if self._match_texts(self.PROPERTY_PARSERS):
1900            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
1901
1902        if self._match(TokenType.DEFAULT) and self._match_texts(self.PROPERTY_PARSERS):
1903            return self.PROPERTY_PARSERS[self._prev.text.upper()](self, default=True)
1904
1905        if self._match_text_seq("COMPOUND", "SORTKEY"):
1906            return self._parse_sortkey(compound=True)
1907
1908        if self._match_text_seq("SQL", "SECURITY"):
1909            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
1910
1911        index = self._index
1912        key = self._parse_column()
1913
1914        if not self._match(TokenType.EQ):
1915            self._retreat(index)
1916            return self._parse_sequence_properties()
1917
1918        # Transform the key to exp.Dot if it's dotted identifiers wrapped in exp.Column or to exp.Var otherwise
1919        if isinstance(key, exp.Column):
1920            key = key.to_dot() if len(key.parts) > 1 else exp.var(key.name)
1921
1922        value = self._parse_bitwise() or self._parse_var(any_token=True)
1923
1924        # Transform the value to exp.Var if it was parsed as exp.Column(exp.Identifier())
1925        if isinstance(value, exp.Column):
1926            value = exp.var(value.name)
1927
1928        return self.expression(exp.Property, this=key, value=value)
1929
1930    def _parse_stored(self) -> exp.FileFormatProperty:
1931        self._match(TokenType.ALIAS)
1932
1933        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
1934        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
1935
1936        return self.expression(
1937            exp.FileFormatProperty,
1938            this=(
1939                self.expression(
1940                    exp.InputOutputFormat, input_format=input_format, output_format=output_format
1941                )
1942                if input_format or output_format
1943                else self._parse_var_or_string() or self._parse_number() or self._parse_id_var()
1944            ),
1945        )
1946
1947    def _parse_unquoted_field(self) -> t.Optional[exp.Expression]:
1948        field = self._parse_field()
1949        if isinstance(field, exp.Identifier) and not field.quoted:
1950            field = exp.var(field)
1951
1952        return field
1953
1954    def _parse_property_assignment(self, exp_class: t.Type[E], **kwargs: t.Any) -> E:
1955        self._match(TokenType.EQ)
1956        self._match(TokenType.ALIAS)
1957
1958        return self.expression(exp_class, this=self._parse_unquoted_field(), **kwargs)
1959
1960    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
1961        properties = []
1962        while True:
1963            if before:
1964                prop = self._parse_property_before()
1965            else:
1966                prop = self._parse_property()
1967            if not prop:
1968                break
1969            for p in ensure_list(prop):
1970                properties.append(p)
1971
1972        if properties:
1973            return self.expression(exp.Properties, expressions=properties)
1974
1975        return None
1976
1977    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
1978        return self.expression(
1979            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
1980        )
1981
1982    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
1983        if self._index >= 2:
1984            pre_volatile_token = self._tokens[self._index - 2]
1985        else:
1986            pre_volatile_token = None
1987
1988        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
1989            return exp.VolatileProperty()
1990
1991        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
1992
1993    def _parse_retention_period(self) -> exp.Var:
1994        # Parse TSQL's HISTORY_RETENTION_PERIOD: {INFINITE | <number> DAY | DAYS | MONTH ...}
1995        number = self._parse_number()
1996        number_str = f"{number} " if number else ""
1997        unit = self._parse_var(any_token=True)
1998        return exp.var(f"{number_str}{unit}")
1999
2000    def _parse_system_versioning_property(
2001        self, with_: bool = False
2002    ) -> exp.WithSystemVersioningProperty:
2003        self._match(TokenType.EQ)
2004        prop = self.expression(
2005            exp.WithSystemVersioningProperty,
2006            **{  # type: ignore
2007                "on": True,
2008                "with": with_,
2009            },
2010        )
2011
2012        if self._match_text_seq("OFF"):
2013            prop.set("on", False)
2014            return prop
2015
2016        self._match(TokenType.ON)
2017        if self._match(TokenType.L_PAREN):
2018            while self._curr and not self._match(TokenType.R_PAREN):
2019                if self._match_text_seq("HISTORY_TABLE", "="):
2020                    prop.set("this", self._parse_table_parts())
2021                elif self._match_text_seq("DATA_CONSISTENCY_CHECK", "="):
2022                    prop.set("data_consistency", self._advance_any() and self._prev.text.upper())
2023                elif self._match_text_seq("HISTORY_RETENTION_PERIOD", "="):
2024                    prop.set("retention_period", self._parse_retention_period())
2025
2026                self._match(TokenType.COMMA)
2027
2028        return prop
2029
2030    def _parse_data_deletion_property(self) -> exp.DataDeletionProperty:
2031        self._match(TokenType.EQ)
2032        on = self._match_text_seq("ON") or not self._match_text_seq("OFF")
2033        prop = self.expression(exp.DataDeletionProperty, on=on)
2034
2035        if self._match(TokenType.L_PAREN):
2036            while self._curr and not self._match(TokenType.R_PAREN):
2037                if self._match_text_seq("FILTER_COLUMN", "="):
2038                    prop.set("filter_column", self._parse_column())
2039                elif self._match_text_seq("RETENTION_PERIOD", "="):
2040                    prop.set("retention_period", self._parse_retention_period())
2041
2042                self._match(TokenType.COMMA)
2043
2044        return prop
2045
2046    def _parse_with_property(self) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
2047        if self._match_text_seq("(", "SYSTEM_VERSIONING"):
2048            prop = self._parse_system_versioning_property(with_=True)
2049            self._match_r_paren()
2050            return prop
2051
2052        if self._match(TokenType.L_PAREN, advance=False):
2053            return self._parse_wrapped_properties()
2054
2055        if self._match_text_seq("JOURNAL"):
2056            return self._parse_withjournaltable()
2057
2058        if self._match_texts(self.VIEW_ATTRIBUTES):
2059            return self.expression(exp.ViewAttributeProperty, this=self._prev.text.upper())
2060
2061        if self._match_text_seq("DATA"):
2062            return self._parse_withdata(no=False)
2063        elif self._match_text_seq("NO", "DATA"):
2064            return self._parse_withdata(no=True)
2065
2066        if self._match(TokenType.SERDE_PROPERTIES, advance=False):
2067            return self._parse_serde_properties(with_=True)
2068
2069        if self._match(TokenType.SCHEMA):
2070            return self.expression(
2071                exp.WithSchemaBindingProperty,
2072                this=self._parse_var_from_options(self.SCHEMA_BINDING_OPTIONS),
2073            )
2074
2075        if not self._next:
2076            return None
2077
2078        return self._parse_withisolatedloading()
2079
2080    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
2081    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
2082        self._match(TokenType.EQ)
2083
2084        user = self._parse_id_var()
2085        self._match(TokenType.PARAMETER)
2086        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
2087
2088        if not user or not host:
2089            return None
2090
2091        return exp.DefinerProperty(this=f"{user}@{host}")
2092
2093    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
2094        self._match(TokenType.TABLE)
2095        self._match(TokenType.EQ)
2096        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
2097
2098    def _parse_log(self, no: bool = False) -> exp.LogProperty:
2099        return self.expression(exp.LogProperty, no=no)
2100
2101    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
2102        return self.expression(exp.JournalProperty, **kwargs)
2103
2104    def _parse_checksum(self) -> exp.ChecksumProperty:
2105        self._match(TokenType.EQ)
2106
2107        on = None
2108        if self._match(TokenType.ON):
2109            on = True
2110        elif self._match_text_seq("OFF"):
2111            on = False
2112
2113        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
2114
2115    def _parse_cluster(self, wrapped: bool = False) -> exp.Cluster:
2116        return self.expression(
2117            exp.Cluster,
2118            expressions=(
2119                self._parse_wrapped_csv(self._parse_ordered)
2120                if wrapped
2121                else self._parse_csv(self._parse_ordered)
2122            ),
2123        )
2124
2125    def _parse_clustered_by(self) -> exp.ClusteredByProperty:
2126        self._match_text_seq("BY")
2127
2128        self._match_l_paren()
2129        expressions = self._parse_csv(self._parse_column)
2130        self._match_r_paren()
2131
2132        if self._match_text_seq("SORTED", "BY"):
2133            self._match_l_paren()
2134            sorted_by = self._parse_csv(self._parse_ordered)
2135            self._match_r_paren()
2136        else:
2137            sorted_by = None
2138
2139        self._match(TokenType.INTO)
2140        buckets = self._parse_number()
2141        self._match_text_seq("BUCKETS")
2142
2143        return self.expression(
2144            exp.ClusteredByProperty,
2145            expressions=expressions,
2146            sorted_by=sorted_by,
2147            buckets=buckets,
2148        )
2149
2150    def _parse_copy_property(self) -> t.Optional[exp.CopyGrantsProperty]:
2151        if not self._match_text_seq("GRANTS"):
2152            self._retreat(self._index - 1)
2153            return None
2154
2155        return self.expression(exp.CopyGrantsProperty)
2156
2157    def _parse_freespace(self) -> exp.FreespaceProperty:
2158        self._match(TokenType.EQ)
2159        return self.expression(
2160            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
2161        )
2162
2163    def _parse_mergeblockratio(
2164        self, no: bool = False, default: bool = False
2165    ) -> exp.MergeBlockRatioProperty:
2166        if self._match(TokenType.EQ):
2167            return self.expression(
2168                exp.MergeBlockRatioProperty,
2169                this=self._parse_number(),
2170                percent=self._match(TokenType.PERCENT),
2171            )
2172
2173        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
2174
2175    def _parse_datablocksize(
2176        self,
2177        default: t.Optional[bool] = None,
2178        minimum: t.Optional[bool] = None,
2179        maximum: t.Optional[bool] = None,
2180    ) -> exp.DataBlocksizeProperty:
2181        self._match(TokenType.EQ)
2182        size = self._parse_number()
2183
2184        units = None
2185        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
2186            units = self._prev.text
2187
2188        return self.expression(
2189            exp.DataBlocksizeProperty,
2190            size=size,
2191            units=units,
2192            default=default,
2193            minimum=minimum,
2194            maximum=maximum,
2195        )
2196
2197    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
2198        self._match(TokenType.EQ)
2199        always = self._match_text_seq("ALWAYS")
2200        manual = self._match_text_seq("MANUAL")
2201        never = self._match_text_seq("NEVER")
2202        default = self._match_text_seq("DEFAULT")
2203
2204        autotemp = None
2205        if self._match_text_seq("AUTOTEMP"):
2206            autotemp = self._parse_schema()
2207
2208        return self.expression(
2209            exp.BlockCompressionProperty,
2210            always=always,
2211            manual=manual,
2212            never=never,
2213            default=default,
2214            autotemp=autotemp,
2215        )
2216
2217    def _parse_withisolatedloading(self) -> t.Optional[exp.IsolatedLoadingProperty]:
2218        index = self._index
2219        no = self._match_text_seq("NO")
2220        concurrent = self._match_text_seq("CONCURRENT")
2221
2222        if not self._match_text_seq("ISOLATED", "LOADING"):
2223            self._retreat(index)
2224            return None
2225
2226        target = self._parse_var_from_options(self.ISOLATED_LOADING_OPTIONS, raise_unmatched=False)
2227        return self.expression(
2228            exp.IsolatedLoadingProperty, no=no, concurrent=concurrent, target=target
2229        )
2230
2231    def _parse_locking(self) -> exp.LockingProperty:
2232        if self._match(TokenType.TABLE):
2233            kind = "TABLE"
2234        elif self._match(TokenType.VIEW):
2235            kind = "VIEW"
2236        elif self._match(TokenType.ROW):
2237            kind = "ROW"
2238        elif self._match_text_seq("DATABASE"):
2239            kind = "DATABASE"
2240        else:
2241            kind = None
2242
2243        if kind in ("DATABASE", "TABLE", "VIEW"):
2244            this = self._parse_table_parts()
2245        else:
2246            this = None
2247
2248        if self._match(TokenType.FOR):
2249            for_or_in = "FOR"
2250        elif self._match(TokenType.IN):
2251            for_or_in = "IN"
2252        else:
2253            for_or_in = None
2254
2255        if self._match_text_seq("ACCESS"):
2256            lock_type = "ACCESS"
2257        elif self._match_texts(("EXCL", "EXCLUSIVE")):
2258            lock_type = "EXCLUSIVE"
2259        elif self._match_text_seq("SHARE"):
2260            lock_type = "SHARE"
2261        elif self._match_text_seq("READ"):
2262            lock_type = "READ"
2263        elif self._match_text_seq("WRITE"):
2264            lock_type = "WRITE"
2265        elif self._match_text_seq("CHECKSUM"):
2266            lock_type = "CHECKSUM"
2267        else:
2268            lock_type = None
2269
2270        override = self._match_text_seq("OVERRIDE")
2271
2272        return self.expression(
2273            exp.LockingProperty,
2274            this=this,
2275            kind=kind,
2276            for_or_in=for_or_in,
2277            lock_type=lock_type,
2278            override=override,
2279        )
2280
2281    def _parse_partition_by(self) -> t.List[exp.Expression]:
2282        if self._match(TokenType.PARTITION_BY):
2283            return self._parse_csv(self._parse_assignment)
2284        return []
2285
2286    def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
2287        def _parse_partition_bound_expr() -> t.Optional[exp.Expression]:
2288            if self._match_text_seq("MINVALUE"):
2289                return exp.var("MINVALUE")
2290            if self._match_text_seq("MAXVALUE"):
2291                return exp.var("MAXVALUE")
2292            return self._parse_bitwise()
2293
2294        this: t.Optional[exp.Expression | t.List[exp.Expression]] = None
2295        expression = None
2296        from_expressions = None
2297        to_expressions = None
2298
2299        if self._match(TokenType.IN):
2300            this = self._parse_wrapped_csv(self._parse_bitwise)
2301        elif self._match(TokenType.FROM):
2302            from_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
2303            self._match_text_seq("TO")
2304            to_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
2305        elif self._match_text_seq("WITH", "(", "MODULUS"):
2306            this = self._parse_number()
2307            self._match_text_seq(",", "REMAINDER")
2308            expression = self._parse_number()
2309            self._match_r_paren()
2310        else:
2311            self.raise_error("Failed to parse partition bound spec.")
2312
2313        return self.expression(
2314            exp.PartitionBoundSpec,
2315            this=this,
2316            expression=expression,
2317            from_expressions=from_expressions,
2318            to_expressions=to_expressions,
2319        )
2320
2321    # https://www.postgresql.org/docs/current/sql-createtable.html
2322    def _parse_partitioned_of(self) -> t.Optional[exp.PartitionedOfProperty]:
2323        if not self._match_text_seq("OF"):
2324            self._retreat(self._index - 1)
2325            return None
2326
2327        this = self._parse_table(schema=True)
2328
2329        if self._match(TokenType.DEFAULT):
2330            expression: exp.Var | exp.PartitionBoundSpec = exp.var("DEFAULT")
2331        elif self._match_text_seq("FOR", "VALUES"):
2332            expression = self._parse_partition_bound_spec()
2333        else:
2334            self.raise_error("Expecting either DEFAULT or FOR VALUES clause.")
2335
2336        return self.expression(exp.PartitionedOfProperty, this=this, expression=expression)
2337
2338    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
2339        self._match(TokenType.EQ)
2340        return self.expression(
2341            exp.PartitionedByProperty,
2342            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
2343        )
2344
2345    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
2346        if self._match_text_seq("AND", "STATISTICS"):
2347            statistics = True
2348        elif self._match_text_seq("AND", "NO", "STATISTICS"):
2349            statistics = False
2350        else:
2351            statistics = None
2352
2353        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
2354
2355    def _parse_contains_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2356        if self._match_text_seq("SQL"):
2357            return self.expression(exp.SqlReadWriteProperty, this="CONTAINS SQL")
2358        return None
2359
2360    def _parse_modifies_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2361        if self._match_text_seq("SQL", "DATA"):
2362            return self.expression(exp.SqlReadWriteProperty, this="MODIFIES SQL DATA")
2363        return None
2364
2365    def _parse_no_property(self) -> t.Optional[exp.Expression]:
2366        if self._match_text_seq("PRIMARY", "INDEX"):
2367            return exp.NoPrimaryIndexProperty()
2368        if self._match_text_seq("SQL"):
2369            return self.expression(exp.SqlReadWriteProperty, this="NO SQL")
2370        return None
2371
2372    def _parse_on_property(self) -> t.Optional[exp.Expression]:
2373        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
2374            return exp.OnCommitProperty()
2375        if self._match_text_seq("COMMIT", "DELETE", "ROWS"):
2376            return exp.OnCommitProperty(delete=True)
2377        return self.expression(exp.OnProperty, this=self._parse_schema(self._parse_id_var()))
2378
2379    def _parse_reads_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2380        if self._match_text_seq("SQL", "DATA"):
2381            return self.expression(exp.SqlReadWriteProperty, this="READS SQL DATA")
2382        return None
2383
2384    def _parse_distkey(self) -> exp.DistKeyProperty:
2385        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
2386
2387    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
2388        table = self._parse_table(schema=True)
2389
2390        options = []
2391        while self._match_texts(("INCLUDING", "EXCLUDING")):
2392            this = self._prev.text.upper()
2393
2394            id_var = self._parse_id_var()
2395            if not id_var:
2396                return None
2397
2398            options.append(
2399                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
2400            )
2401
2402        return self.expression(exp.LikeProperty, this=table, expressions=options)
2403
2404    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
2405        return self.expression(
2406            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
2407        )
2408
2409    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
2410        self._match(TokenType.EQ)
2411        return self.expression(
2412            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
2413        )
2414
2415    def _parse_remote_with_connection(self) -> exp.RemoteWithConnectionModelProperty:
2416        self._match_text_seq("WITH", "CONNECTION")
2417        return self.expression(
2418            exp.RemoteWithConnectionModelProperty, this=self._parse_table_parts()
2419        )
2420
2421    def _parse_returns(self) -> exp.ReturnsProperty:
2422        value: t.Optional[exp.Expression]
2423        null = None
2424        is_table = self._match(TokenType.TABLE)
2425
2426        if is_table:
2427            if self._match(TokenType.LT):
2428                value = self.expression(
2429                    exp.Schema,
2430                    this="TABLE",
2431                    expressions=self._parse_csv(self._parse_struct_types),
2432                )
2433                if not self._match(TokenType.GT):
2434                    self.raise_error("Expecting >")
2435            else:
2436                value = self._parse_schema(exp.var("TABLE"))
2437        elif self._match_text_seq("NULL", "ON", "NULL", "INPUT"):
2438            null = True
2439            value = None
2440        else:
2441            value = self._parse_types()
2442
2443        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table, null=null)
2444
2445    def _parse_describe(self) -> exp.Describe:
2446        kind = self._match_set(self.CREATABLES) and self._prev.text
2447        style = self._match_texts(("EXTENDED", "FORMATTED", "HISTORY")) and self._prev.text.upper()
2448        if self._match(TokenType.DOT):
2449            style = None
2450            self._retreat(self._index - 2)
2451        this = self._parse_table(schema=True)
2452        properties = self._parse_properties()
2453        expressions = properties.expressions if properties else None
2454        return self.expression(
2455            exp.Describe, this=this, style=style, kind=kind, expressions=expressions
2456        )
2457
2458    def _parse_insert(self) -> exp.Insert:
2459        comments = ensure_list(self._prev_comments)
2460        hint = self._parse_hint()
2461        overwrite = self._match(TokenType.OVERWRITE)
2462        ignore = self._match(TokenType.IGNORE)
2463        local = self._match_text_seq("LOCAL")
2464        alternative = None
2465        is_function = None
2466
2467        if self._match_text_seq("DIRECTORY"):
2468            this: t.Optional[exp.Expression] = self.expression(
2469                exp.Directory,
2470                this=self._parse_var_or_string(),
2471                local=local,
2472                row_format=self._parse_row_format(match_row=True),
2473            )
2474        else:
2475            if self._match(TokenType.OR):
2476                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
2477
2478            self._match(TokenType.INTO)
2479            comments += ensure_list(self._prev_comments)
2480            self._match(TokenType.TABLE)
2481            is_function = self._match(TokenType.FUNCTION)
2482
2483            this = (
2484                self._parse_table(schema=True, parse_partition=True)
2485                if not is_function
2486                else self._parse_function()
2487            )
2488
2489        returning = self._parse_returning()
2490
2491        return self.expression(
2492            exp.Insert,
2493            comments=comments,
2494            hint=hint,
2495            is_function=is_function,
2496            this=this,
2497            stored=self._match_text_seq("STORED") and self._parse_stored(),
2498            by_name=self._match_text_seq("BY", "NAME"),
2499            exists=self._parse_exists(),
2500            where=self._match_pair(TokenType.REPLACE, TokenType.WHERE) and self._parse_assignment(),
2501            expression=self._parse_derived_table_values() or self._parse_ddl_select(),
2502            conflict=self._parse_on_conflict(),
2503            returning=returning or self._parse_returning(),
2504            overwrite=overwrite,
2505            alternative=alternative,
2506            ignore=ignore,
2507        )
2508
2509    def _parse_kill(self) -> exp.Kill:
2510        kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
2511
2512        return self.expression(
2513            exp.Kill,
2514            this=self._parse_primary(),
2515            kind=kind,
2516        )
2517
2518    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
2519        conflict = self._match_text_seq("ON", "CONFLICT")
2520        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
2521
2522        if not conflict and not duplicate:
2523            return None
2524
2525        conflict_keys = None
2526        constraint = None
2527
2528        if conflict:
2529            if self._match_text_seq("ON", "CONSTRAINT"):
2530                constraint = self._parse_id_var()
2531            elif self._match(TokenType.L_PAREN):
2532                conflict_keys = self._parse_csv(self._parse_id_var)
2533                self._match_r_paren()
2534
2535        action = self._parse_var_from_options(self.CONFLICT_ACTIONS)
2536        if self._prev.token_type == TokenType.UPDATE:
2537            self._match(TokenType.SET)
2538            expressions = self._parse_csv(self._parse_equality)
2539        else:
2540            expressions = None
2541
2542        return self.expression(
2543            exp.OnConflict,
2544            duplicate=duplicate,
2545            expressions=expressions,
2546            action=action,
2547            conflict_keys=conflict_keys,
2548            constraint=constraint,
2549        )
2550
2551    def _parse_returning(self) -> t.Optional[exp.Returning]:
2552        if not self._match(TokenType.RETURNING):
2553            return None
2554        return self.expression(
2555            exp.Returning,
2556            expressions=self._parse_csv(self._parse_expression),
2557            into=self._match(TokenType.INTO) and self._parse_table_part(),
2558        )
2559
2560    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2561        if not self._match(TokenType.FORMAT):
2562            return None
2563        return self._parse_row_format()
2564
2565    def _parse_serde_properties(self, with_: bool = False) -> t.Optional[exp.SerdeProperties]:
2566        index = self._index
2567        with_ = with_ or self._match_text_seq("WITH")
2568
2569        if not self._match(TokenType.SERDE_PROPERTIES):
2570            self._retreat(index)
2571            return None
2572        return self.expression(
2573            exp.SerdeProperties,
2574            **{  # type: ignore
2575                "expressions": self._parse_wrapped_properties(),
2576                "with": with_,
2577            },
2578        )
2579
2580    def _parse_row_format(
2581        self, match_row: bool = False
2582    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2583        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
2584            return None
2585
2586        if self._match_text_seq("SERDE"):
2587            this = self._parse_string()
2588
2589            serde_properties = self._parse_serde_properties()
2590
2591            return self.expression(
2592                exp.RowFormatSerdeProperty, this=this, serde_properties=serde_properties
2593            )
2594
2595        self._match_text_seq("DELIMITED")
2596
2597        kwargs = {}
2598
2599        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
2600            kwargs["fields"] = self._parse_string()
2601            if self._match_text_seq("ESCAPED", "BY"):
2602                kwargs["escaped"] = self._parse_string()
2603        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
2604            kwargs["collection_items"] = self._parse_string()
2605        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
2606            kwargs["map_keys"] = self._parse_string()
2607        if self._match_text_seq("LINES", "TERMINATED", "BY"):
2608            kwargs["lines"] = self._parse_string()
2609        if self._match_text_seq("NULL", "DEFINED", "AS"):
2610            kwargs["null"] = self._parse_string()
2611
2612        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
2613
2614    def _parse_load(self) -> exp.LoadData | exp.Command:
2615        if self._match_text_seq("DATA"):
2616            local = self._match_text_seq("LOCAL")
2617            self._match_text_seq("INPATH")
2618            inpath = self._parse_string()
2619            overwrite = self._match(TokenType.OVERWRITE)
2620            self._match_pair(TokenType.INTO, TokenType.TABLE)
2621
2622            return self.expression(
2623                exp.LoadData,
2624                this=self._parse_table(schema=True),
2625                local=local,
2626                overwrite=overwrite,
2627                inpath=inpath,
2628                partition=self._parse_partition(),
2629                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
2630                serde=self._match_text_seq("SERDE") and self._parse_string(),
2631            )
2632        return self._parse_as_command(self._prev)
2633
2634    def _parse_delete(self) -> exp.Delete:
2635        # This handles MySQL's "Multiple-Table Syntax"
2636        # https://dev.mysql.com/doc/refman/8.0/en/delete.html
2637        tables = None
2638        comments = self._prev_comments
2639        if not self._match(TokenType.FROM, advance=False):
2640            tables = self._parse_csv(self._parse_table) or None
2641
2642        returning = self._parse_returning()
2643
2644        return self.expression(
2645            exp.Delete,
2646            comments=comments,
2647            tables=tables,
2648            this=self._match(TokenType.FROM) and self._parse_table(joins=True),
2649            using=self._match(TokenType.USING) and self._parse_table(joins=True),
2650            where=self._parse_where(),
2651            returning=returning or self._parse_returning(),
2652            limit=self._parse_limit(),
2653        )
2654
2655    def _parse_update(self) -> exp.Update:
2656        comments = self._prev_comments
2657        this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
2658        expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
2659        returning = self._parse_returning()
2660        return self.expression(
2661            exp.Update,
2662            comments=comments,
2663            **{  # type: ignore
2664                "this": this,
2665                "expressions": expressions,
2666                "from": self._parse_from(joins=True),
2667                "where": self._parse_where(),
2668                "returning": returning or self._parse_returning(),
2669                "order": self._parse_order(),
2670                "limit": self._parse_limit(),
2671            },
2672        )
2673
2674    def _parse_uncache(self) -> exp.Uncache:
2675        if not self._match(TokenType.TABLE):
2676            self.raise_error("Expecting TABLE after UNCACHE")
2677
2678        return self.expression(
2679            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
2680        )
2681
2682    def _parse_cache(self) -> exp.Cache:
2683        lazy = self._match_text_seq("LAZY")
2684        self._match(TokenType.TABLE)
2685        table = self._parse_table(schema=True)
2686
2687        options = []
2688        if self._match_text_seq("OPTIONS"):
2689            self._match_l_paren()
2690            k = self._parse_string()
2691            self._match(TokenType.EQ)
2692            v = self._parse_string()
2693            options = [k, v]
2694            self._match_r_paren()
2695
2696        self._match(TokenType.ALIAS)
2697        return self.expression(
2698            exp.Cache,
2699            this=table,
2700            lazy=lazy,
2701            options=options,
2702            expression=self._parse_select(nested=True),
2703        )
2704
2705    def _parse_partition(self) -> t.Optional[exp.Partition]:
2706        if not self._match(TokenType.PARTITION):
2707            return None
2708
2709        return self.expression(
2710            exp.Partition, expressions=self._parse_wrapped_csv(self._parse_assignment)
2711        )
2712
2713    def _parse_value(self) -> t.Optional[exp.Tuple]:
2714        if self._match(TokenType.L_PAREN):
2715            expressions = self._parse_csv(self._parse_expression)
2716            self._match_r_paren()
2717            return self.expression(exp.Tuple, expressions=expressions)
2718
2719        # In some dialects we can have VALUES 1, 2 which results in 1 column & 2 rows.
2720        expression = self._parse_expression()
2721        if expression:
2722            return self.expression(exp.Tuple, expressions=[expression])
2723        return None
2724
2725    def _parse_projections(self) -> t.List[exp.Expression]:
2726        return self._parse_expressions()
2727
2728    def _parse_select(
2729        self,
2730        nested: bool = False,
2731        table: bool = False,
2732        parse_subquery_alias: bool = True,
2733        parse_set_operation: bool = True,
2734    ) -> t.Optional[exp.Expression]:
2735        cte = self._parse_with()
2736
2737        if cte:
2738            this = self._parse_statement()
2739
2740            if not this:
2741                self.raise_error("Failed to parse any statement following CTE")
2742                return cte
2743
2744            if "with" in this.arg_types:
2745                this.set("with", cte)
2746            else:
2747                self.raise_error(f"{this.key} does not support CTE")
2748                this = cte
2749
2750            return this
2751
2752        # duckdb supports leading with FROM x
2753        from_ = self._parse_from() if self._match(TokenType.FROM, advance=False) else None
2754
2755        if self._match(TokenType.SELECT):
2756            comments = self._prev_comments
2757
2758            hint = self._parse_hint()
2759
2760            if self._next and not self._next.token_type == TokenType.DOT:
2761                all_ = self._match(TokenType.ALL)
2762                distinct = self._match_set(self.DISTINCT_TOKENS)
2763            else:
2764                all_, distinct = None, None
2765
2766            kind = (
2767                self._match(TokenType.ALIAS)
2768                and self._match_texts(("STRUCT", "VALUE"))
2769                and self._prev.text.upper()
2770            )
2771
2772            if distinct:
2773                distinct = self.expression(
2774                    exp.Distinct,
2775                    on=self._parse_value() if self._match(TokenType.ON) else None,
2776                )
2777
2778            if all_ and distinct:
2779                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
2780
2781            limit = self._parse_limit(top=True)
2782            projections = self._parse_projections()
2783
2784            this = self.expression(
2785                exp.Select,
2786                kind=kind,
2787                hint=hint,
2788                distinct=distinct,
2789                expressions=projections,
2790                limit=limit,
2791            )
2792            this.comments = comments
2793
2794            into = self._parse_into()
2795            if into:
2796                this.set("into", into)
2797
2798            if not from_:
2799                from_ = self._parse_from()
2800
2801            if from_:
2802                this.set("from", from_)
2803
2804            this = self._parse_query_modifiers(this)
2805        elif (table or nested) and self._match(TokenType.L_PAREN):
2806            if self._match(TokenType.PIVOT):
2807                this = self._parse_simplified_pivot()
2808            elif self._match(TokenType.FROM):
2809                this = exp.select("*").from_(
2810                    t.cast(exp.From, self._parse_from(skip_from_token=True))
2811                )
2812            else:
2813                this = (
2814                    self._parse_table()
2815                    if table
2816                    else self._parse_select(nested=True, parse_set_operation=False)
2817                )
2818                this = self._parse_query_modifiers(self._parse_set_operations(this))
2819
2820            self._match_r_paren()
2821
2822            # We return early here so that the UNION isn't attached to the subquery by the
2823            # following call to _parse_set_operations, but instead becomes the parent node
2824            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
2825        elif self._match(TokenType.VALUES, advance=False):
2826            this = self._parse_derived_table_values()
2827        elif from_:
2828            this = exp.select("*").from_(from_.this, copy=False)
2829        elif self._match(TokenType.SUMMARIZE):
2830            table = self._match(TokenType.TABLE)
2831            this = self._parse_select() or self._parse_string() or self._parse_table()
2832            return self.expression(exp.Summarize, this=this, table=table)
2833        else:
2834            this = None
2835
2836        return self._parse_set_operations(this) if parse_set_operation else this
2837
2838    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
2839        if not skip_with_token and not self._match(TokenType.WITH):
2840            return None
2841
2842        comments = self._prev_comments
2843        recursive = self._match(TokenType.RECURSIVE)
2844
2845        expressions = []
2846        while True:
2847            expressions.append(self._parse_cte())
2848
2849            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
2850                break
2851            else:
2852                self._match(TokenType.WITH)
2853
2854        return self.expression(
2855            exp.With, comments=comments, expressions=expressions, recursive=recursive
2856        )
2857
2858    def _parse_cte(self) -> exp.CTE:
2859        alias = self._parse_table_alias(self.ID_VAR_TOKENS)
2860        if not alias or not alias.this:
2861            self.raise_error("Expected CTE to have alias")
2862
2863        self._match(TokenType.ALIAS)
2864        comments = self._prev_comments
2865
2866        if self._match_text_seq("NOT", "MATERIALIZED"):
2867            materialized = False
2868        elif self._match_text_seq("MATERIALIZED"):
2869            materialized = True
2870        else:
2871            materialized = None
2872
2873        return self.expression(
2874            exp.CTE,
2875            this=self._parse_wrapped(self._parse_statement),
2876            alias=alias,
2877            materialized=materialized,
2878            comments=comments,
2879        )
2880
2881    def _parse_table_alias(
2882        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
2883    ) -> t.Optional[exp.TableAlias]:
2884        any_token = self._match(TokenType.ALIAS)
2885        alias = (
2886            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
2887            or self._parse_string_as_identifier()
2888        )
2889
2890        index = self._index
2891        if self._match(TokenType.L_PAREN):
2892            columns = self._parse_csv(self._parse_function_parameter)
2893            self._match_r_paren() if columns else self._retreat(index)
2894        else:
2895            columns = None
2896
2897        if not alias and not columns:
2898            return None
2899
2900        table_alias = self.expression(exp.TableAlias, this=alias, columns=columns)
2901
2902        # We bubble up comments from the Identifier to the TableAlias
2903        if isinstance(alias, exp.Identifier):
2904            table_alias.add_comments(alias.pop_comments())
2905
2906        return table_alias
2907
2908    def _parse_subquery(
2909        self, this: t.Optional[exp.Expression], parse_alias: bool = True
2910    ) -> t.Optional[exp.Subquery]:
2911        if not this:
2912            return None
2913
2914        return self.expression(
2915            exp.Subquery,
2916            this=this,
2917            pivots=self._parse_pivots(),
2918            alias=self._parse_table_alias() if parse_alias else None,
2919        )
2920
2921    def _implicit_unnests_to_explicit(self, this: E) -> E:
2922        from sqlglot.optimizer.normalize_identifiers import normalize_identifiers as _norm
2923
2924        refs = {_norm(this.args["from"].this.copy(), dialect=self.dialect).alias_or_name}
2925        for i, join in enumerate(this.args.get("joins") or []):
2926            table = join.this
2927            normalized_table = table.copy()
2928            normalized_table.meta["maybe_column"] = True
2929            normalized_table = _norm(normalized_table, dialect=self.dialect)
2930
2931            if isinstance(table, exp.Table) and not join.args.get("on"):
2932                if normalized_table.parts[0].name in refs:
2933                    table_as_column = table.to_column()
2934                    unnest = exp.Unnest(expressions=[table_as_column])
2935
2936                    # Table.to_column creates a parent Alias node that we want to convert to
2937                    # a TableAlias and attach to the Unnest, so it matches the parser's output
2938                    if isinstance(table.args.get("alias"), exp.TableAlias):
2939                        table_as_column.replace(table_as_column.this)
2940                        exp.alias_(unnest, None, table=[table.args["alias"].this], copy=False)
2941
2942                    table.replace(unnest)
2943
2944            refs.add(normalized_table.alias_or_name)
2945
2946        return this
2947
2948    def _parse_query_modifiers(
2949        self, this: t.Optional[exp.Expression]
2950    ) -> t.Optional[exp.Expression]:
2951        if isinstance(this, (exp.Query, exp.Table)):
2952            for join in self._parse_joins():
2953                this.append("joins", join)
2954            for lateral in iter(self._parse_lateral, None):
2955                this.append("laterals", lateral)
2956
2957            while True:
2958                if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
2959                    parser = self.QUERY_MODIFIER_PARSERS[self._curr.token_type]
2960                    key, expression = parser(self)
2961
2962                    if expression:
2963                        this.set(key, expression)
2964                        if key == "limit":
2965                            offset = expression.args.pop("offset", None)
2966
2967                            if offset:
2968                                offset = exp.Offset(expression=offset)
2969                                this.set("offset", offset)
2970
2971                                limit_by_expressions = expression.expressions
2972                                expression.set("expressions", None)
2973                                offset.set("expressions", limit_by_expressions)
2974                        continue
2975                break
2976
2977        if self.SUPPORTS_IMPLICIT_UNNEST and this and this.args.get("from"):
2978            this = self._implicit_unnests_to_explicit(this)
2979
2980        return this
2981
2982    def _parse_hint(self) -> t.Optional[exp.Hint]:
2983        if self._match(TokenType.HINT):
2984            hints = []
2985            for hint in iter(
2986                lambda: self._parse_csv(
2987                    lambda: self._parse_function() or self._parse_var(upper=True)
2988                ),
2989                [],
2990            ):
2991                hints.extend(hint)
2992
2993            if not self._match_pair(TokenType.STAR, TokenType.SLASH):
2994                self.raise_error("Expected */ after HINT")
2995
2996            return self.expression(exp.Hint, expressions=hints)
2997
2998        return None
2999
3000    def _parse_into(self) -> t.Optional[exp.Into]:
3001        if not self._match(TokenType.INTO):
3002            return None
3003
3004        temp = self._match(TokenType.TEMPORARY)
3005        unlogged = self._match_text_seq("UNLOGGED")
3006        self._match(TokenType.TABLE)
3007
3008        return self.expression(
3009            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
3010        )
3011
3012    def _parse_from(
3013        self, joins: bool = False, skip_from_token: bool = False
3014    ) -> t.Optional[exp.From]:
3015        if not skip_from_token and not self._match(TokenType.FROM):
3016            return None
3017
3018        return self.expression(
3019            exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
3020        )
3021
3022    def _parse_match_recognize_measure(self) -> exp.MatchRecognizeMeasure:
3023        return self.expression(
3024            exp.MatchRecognizeMeasure,
3025            window_frame=self._match_texts(("FINAL", "RUNNING")) and self._prev.text.upper(),
3026            this=self._parse_expression(),
3027        )
3028
3029    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
3030        if not self._match(TokenType.MATCH_RECOGNIZE):
3031            return None
3032
3033        self._match_l_paren()
3034
3035        partition = self._parse_partition_by()
3036        order = self._parse_order()
3037
3038        measures = (
3039            self._parse_csv(self._parse_match_recognize_measure)
3040            if self._match_text_seq("MEASURES")
3041            else None
3042        )
3043
3044        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
3045            rows = exp.var("ONE ROW PER MATCH")
3046        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
3047            text = "ALL ROWS PER MATCH"
3048            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
3049                text += " SHOW EMPTY MATCHES"
3050            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
3051                text += " OMIT EMPTY MATCHES"
3052            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
3053                text += " WITH UNMATCHED ROWS"
3054            rows = exp.var(text)
3055        else:
3056            rows = None
3057
3058        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
3059            text = "AFTER MATCH SKIP"
3060            if self._match_text_seq("PAST", "LAST", "ROW"):
3061                text += " PAST LAST ROW"
3062            elif self._match_text_seq("TO", "NEXT", "ROW"):
3063                text += " TO NEXT ROW"
3064            elif self._match_text_seq("TO", "FIRST"):
3065                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
3066            elif self._match_text_seq("TO", "LAST"):
3067                text += f" TO LAST {self._advance_any().text}"  # type: ignore
3068            after = exp.var(text)
3069        else:
3070            after = None
3071
3072        if self._match_text_seq("PATTERN"):
3073            self._match_l_paren()
3074
3075            if not self._curr:
3076                self.raise_error("Expecting )", self._curr)
3077
3078            paren = 1
3079            start = self._curr
3080
3081            while self._curr and paren > 0:
3082                if self._curr.token_type == TokenType.L_PAREN:
3083                    paren += 1
3084                if self._curr.token_type == TokenType.R_PAREN:
3085                    paren -= 1
3086
3087                end = self._prev
3088                self._advance()
3089
3090            if paren > 0:
3091                self.raise_error("Expecting )", self._curr)
3092
3093            pattern = exp.var(self._find_sql(start, end))
3094        else:
3095            pattern = None
3096
3097        define = (
3098            self._parse_csv(self._parse_name_as_expression)
3099            if self._match_text_seq("DEFINE")
3100            else None
3101        )
3102
3103        self._match_r_paren()
3104
3105        return self.expression(
3106            exp.MatchRecognize,
3107            partition_by=partition,
3108            order=order,
3109            measures=measures,
3110            rows=rows,
3111            after=after,
3112            pattern=pattern,
3113            define=define,
3114            alias=self._parse_table_alias(),
3115        )
3116
3117    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
3118        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
3119        if not cross_apply and self._match_pair(TokenType.OUTER, TokenType.APPLY):
3120            cross_apply = False
3121
3122        if cross_apply is not None:
3123            this = self._parse_select(table=True)
3124            view = None
3125            outer = None
3126        elif self._match(TokenType.LATERAL):
3127            this = self._parse_select(table=True)
3128            view = self._match(TokenType.VIEW)
3129            outer = self._match(TokenType.OUTER)
3130        else:
3131            return None
3132
3133        if not this:
3134            this = (
3135                self._parse_unnest()
3136                or self._parse_function()
3137                or self._parse_id_var(any_token=False)
3138            )
3139
3140            while self._match(TokenType.DOT):
3141                this = exp.Dot(
3142                    this=this,
3143                    expression=self._parse_function() or self._parse_id_var(any_token=False),
3144                )
3145
3146        if view:
3147            table = self._parse_id_var(any_token=False)
3148            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
3149            table_alias: t.Optional[exp.TableAlias] = self.expression(
3150                exp.TableAlias, this=table, columns=columns
3151            )
3152        elif isinstance(this, (exp.Subquery, exp.Unnest)) and this.alias:
3153            # We move the alias from the lateral's child node to the lateral itself
3154            table_alias = this.args["alias"].pop()
3155        else:
3156            table_alias = self._parse_table_alias()
3157
3158        return self.expression(
3159            exp.Lateral,
3160            this=this,
3161            view=view,
3162            outer=outer,
3163            alias=table_alias,
3164            cross_apply=cross_apply,
3165        )
3166
3167    def _parse_join_parts(
3168        self,
3169    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
3170        return (
3171            self._match_set(self.JOIN_METHODS) and self._prev,
3172            self._match_set(self.JOIN_SIDES) and self._prev,
3173            self._match_set(self.JOIN_KINDS) and self._prev,
3174        )
3175
3176    def _parse_join(
3177        self, skip_join_token: bool = False, parse_bracket: bool = False
3178    ) -> t.Optional[exp.Join]:
3179        if self._match(TokenType.COMMA):
3180            return self.expression(exp.Join, this=self._parse_table())
3181
3182        index = self._index
3183        method, side, kind = self._parse_join_parts()
3184        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
3185        join = self._match(TokenType.JOIN) or (kind and kind.token_type == TokenType.STRAIGHT_JOIN)
3186
3187        if not skip_join_token and not join:
3188            self._retreat(index)
3189            kind = None
3190            method = None
3191            side = None
3192
3193        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
3194        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
3195
3196        if not skip_join_token and not join and not outer_apply and not cross_apply:
3197            return None
3198
3199        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table(parse_bracket=parse_bracket)}
3200
3201        if method:
3202            kwargs["method"] = method.text
3203        if side:
3204            kwargs["side"] = side.text
3205        if kind:
3206            kwargs["kind"] = kind.text
3207        if hint:
3208            kwargs["hint"] = hint
3209
3210        if self._match(TokenType.MATCH_CONDITION):
3211            kwargs["match_condition"] = self._parse_wrapped(self._parse_comparison)
3212
3213        if self._match(TokenType.ON):
3214            kwargs["on"] = self._parse_assignment()
3215        elif self._match(TokenType.USING):
3216            kwargs["using"] = self._parse_wrapped_id_vars()
3217        elif not isinstance(kwargs["this"], exp.Unnest) and not (
3218            kind and kind.token_type == TokenType.CROSS
3219        ):
3220            index = self._index
3221            joins: t.Optional[list] = list(self._parse_joins())
3222
3223            if joins and self._match(TokenType.ON):
3224                kwargs["on"] = self._parse_assignment()
3225            elif joins and self._match(TokenType.USING):
3226                kwargs["using"] = self._parse_wrapped_id_vars()
3227            else:
3228                joins = None
3229                self._retreat(index)
3230
3231            kwargs["this"].set("joins", joins if joins else None)
3232
3233        comments = [c for token in (method, side, kind) if token for c in token.comments]
3234        return self.expression(exp.Join, comments=comments, **kwargs)
3235
3236    def _parse_opclass(self) -> t.Optional[exp.Expression]:
3237        this = self._parse_assignment()
3238
3239        if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
3240            return this
3241
3242        if not self._match_set(self.OPTYPE_FOLLOW_TOKENS, advance=False):
3243            return self.expression(exp.Opclass, this=this, expression=self._parse_table_parts())
3244
3245        return this
3246
3247    def _parse_index_params(self) -> exp.IndexParameters:
3248        using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
3249
3250        if self._match(TokenType.L_PAREN, advance=False):
3251            columns = self._parse_wrapped_csv(self._parse_with_operator)
3252        else:
3253            columns = None
3254
3255        include = self._parse_wrapped_id_vars() if self._match_text_seq("INCLUDE") else None
3256        partition_by = self._parse_partition_by()
3257        with_storage = self._match(TokenType.WITH) and self._parse_wrapped_properties()
3258        tablespace = (
3259            self._parse_var(any_token=True)
3260            if self._match_text_seq("USING", "INDEX", "TABLESPACE")
3261            else None
3262        )
3263        where = self._parse_where()
3264
3265        on = self._parse_field() if self._match(TokenType.ON) else None
3266
3267        return self.expression(
3268            exp.IndexParameters,
3269            using=using,
3270            columns=columns,
3271            include=include,
3272            partition_by=partition_by,
3273            where=where,
3274            with_storage=with_storage,
3275            tablespace=tablespace,
3276            on=on,
3277        )
3278
3279    def _parse_index(
3280        self, index: t.Optional[exp.Expression] = None, anonymous: bool = False
3281    ) -> t.Optional[exp.Index]:
3282        if index or anonymous:
3283            unique = None
3284            primary = None
3285            amp = None
3286
3287            self._match(TokenType.ON)
3288            self._match(TokenType.TABLE)  # hive
3289            table = self._parse_table_parts(schema=True)
3290        else:
3291            unique = self._match(TokenType.UNIQUE)
3292            primary = self._match_text_seq("PRIMARY")
3293            amp = self._match_text_seq("AMP")
3294
3295            if not self._match(TokenType.INDEX):
3296                return None
3297
3298            index = self._parse_id_var()
3299            table = None
3300
3301        params = self._parse_index_params()
3302
3303        return self.expression(
3304            exp.Index,
3305            this=index,
3306            table=table,
3307            unique=unique,
3308            primary=primary,
3309            amp=amp,
3310            params=params,
3311        )
3312
3313    def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
3314        hints: t.List[exp.Expression] = []
3315        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
3316            # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
3317            hints.append(
3318                self.expression(
3319                    exp.WithTableHint,
3320                    expressions=self._parse_csv(
3321                        lambda: self._parse_function() or self._parse_var(any_token=True)
3322                    ),
3323                )
3324            )
3325            self._match_r_paren()
3326        else:
3327            # https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
3328            while self._match_set(self.TABLE_INDEX_HINT_TOKENS):
3329                hint = exp.IndexTableHint(this=self._prev.text.upper())
3330
3331                self._match_set((TokenType.INDEX, TokenType.KEY))
3332                if self._match(TokenType.FOR):
3333                    hint.set("target", self._advance_any() and self._prev.text.upper())
3334
3335                hint.set("expressions", self._parse_wrapped_id_vars())
3336                hints.append(hint)
3337
3338        return hints or None
3339
3340    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
3341        return (
3342            (not schema and self._parse_function(optional_parens=False))
3343            or self._parse_id_var(any_token=False)
3344            or self._parse_string_as_identifier()
3345            or self._parse_placeholder()
3346        )
3347
3348    def _parse_table_parts(
3349        self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
3350    ) -> exp.Table:
3351        catalog = None
3352        db = None
3353        table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
3354
3355        while self._match(TokenType.DOT):
3356            if catalog:
3357                # This allows nesting the table in arbitrarily many dot expressions if needed
3358                table = self.expression(
3359                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
3360                )
3361            else:
3362                catalog = db
3363                db = table
3364                # "" used for tsql FROM a..b case
3365                table = self._parse_table_part(schema=schema) or ""
3366
3367        if (
3368            wildcard
3369            and self._is_connected()
3370            and (isinstance(table, exp.Identifier) or not table)
3371            and self._match(TokenType.STAR)
3372        ):
3373            if isinstance(table, exp.Identifier):
3374                table.args["this"] += "*"
3375            else:
3376                table = exp.Identifier(this="*")
3377
3378        # We bubble up comments from the Identifier to the Table
3379        comments = table.pop_comments() if isinstance(table, exp.Expression) else None
3380
3381        if is_db_reference:
3382            catalog = db
3383            db = table
3384            table = None
3385
3386        if not table and not is_db_reference:
3387            self.raise_error(f"Expected table name but got {self._curr}")
3388        if not db and is_db_reference:
3389            self.raise_error(f"Expected database name but got {self._curr}")
3390
3391        table = self.expression(
3392            exp.Table,
3393            comments=comments,
3394            this=table,
3395            db=db,
3396            catalog=catalog,
3397        )
3398
3399        changes = self._parse_changes()
3400        if changes:
3401            table.set("changes", changes)
3402
3403        at_before = self._parse_historical_data()
3404        if at_before:
3405            table.set("when", at_before)
3406
3407        pivots = self._parse_pivots()
3408        if pivots:
3409            table.set("pivots", pivots)
3410
3411        return table
3412
3413    def _parse_table(
3414        self,
3415        schema: bool = False,
3416        joins: bool = False,
3417        alias_tokens: t.Optional[t.Collection[TokenType]] = None,
3418        parse_bracket: bool = False,
3419        is_db_reference: bool = False,
3420        parse_partition: bool = False,
3421    ) -> t.Optional[exp.Expression]:
3422        lateral = self._parse_lateral()
3423        if lateral:
3424            return lateral
3425
3426        unnest = self._parse_unnest()
3427        if unnest:
3428            return unnest
3429
3430        values = self._parse_derived_table_values()
3431        if values:
3432            return values
3433
3434        subquery = self._parse_select(table=True)
3435        if subquery:
3436            if not subquery.args.get("pivots"):
3437                subquery.set("pivots", self._parse_pivots())
3438            return subquery
3439
3440        bracket = parse_bracket and self._parse_bracket(None)
3441        bracket = self.expression(exp.Table, this=bracket) if bracket else None
3442
3443        rows_from = self._match_text_seq("ROWS", "FROM") and self._parse_wrapped_csv(
3444            self._parse_table
3445        )
3446        rows_from = self.expression(exp.Table, rows_from=rows_from) if rows_from else None
3447
3448        only = self._match(TokenType.ONLY)
3449
3450        this = t.cast(
3451            exp.Expression,
3452            bracket
3453            or rows_from
3454            or self._parse_bracket(
3455                self._parse_table_parts(schema=schema, is_db_reference=is_db_reference)
3456            ),
3457        )
3458
3459        if only:
3460            this.set("only", only)
3461
3462        # Postgres supports a wildcard (table) suffix operator, which is a no-op in this context
3463        self._match_text_seq("*")
3464
3465        parse_partition = parse_partition or self.SUPPORTS_PARTITION_SELECTION
3466        if parse_partition and self._match(TokenType.PARTITION, advance=False):
3467            this.set("partition", self._parse_partition())
3468
3469        if schema:
3470            return self._parse_schema(this=this)
3471
3472        version = self._parse_version()
3473
3474        if version:
3475            this.set("version", version)
3476
3477        if self.dialect.ALIAS_POST_TABLESAMPLE:
3478            table_sample = self._parse_table_sample()
3479
3480        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
3481        if alias:
3482            this.set("alias", alias)
3483
3484        if isinstance(this, exp.Table) and self._match_text_seq("AT"):
3485            return self.expression(
3486                exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
3487            )
3488
3489        this.set("hints", self._parse_table_hints())
3490
3491        if not this.args.get("pivots"):
3492            this.set("pivots", self._parse_pivots())
3493
3494        if not self.dialect.ALIAS_POST_TABLESAMPLE:
3495            table_sample = self._parse_table_sample()
3496
3497        if table_sample:
3498            table_sample.set("this", this)
3499            this = table_sample
3500
3501        if joins:
3502            for join in self._parse_joins():
3503                this.append("joins", join)
3504
3505        if self._match_pair(TokenType.WITH, TokenType.ORDINALITY):
3506            this.set("ordinality", True)
3507            this.set("alias", self._parse_table_alias())
3508
3509        return this
3510
3511    def _parse_version(self) -> t.Optional[exp.Version]:
3512        if self._match(TokenType.TIMESTAMP_SNAPSHOT):
3513            this = "TIMESTAMP"
3514        elif self._match(TokenType.VERSION_SNAPSHOT):
3515            this = "VERSION"
3516        else:
3517            return None
3518
3519        if self._match_set((TokenType.FROM, TokenType.BETWEEN)):
3520            kind = self._prev.text.upper()
3521            start = self._parse_bitwise()
3522            self._match_texts(("TO", "AND"))
3523            end = self._parse_bitwise()
3524            expression: t.Optional[exp.Expression] = self.expression(
3525                exp.Tuple, expressions=[start, end]
3526            )
3527        elif self._match_text_seq("CONTAINED", "IN"):
3528            kind = "CONTAINED IN"
3529            expression = self.expression(
3530                exp.Tuple, expressions=self._parse_wrapped_csv(self._parse_bitwise)
3531            )
3532        elif self._match(TokenType.ALL):
3533            kind = "ALL"
3534            expression = None
3535        else:
3536            self._match_text_seq("AS", "OF")
3537            kind = "AS OF"
3538            expression = self._parse_type()
3539
3540        return self.expression(exp.Version, this=this, expression=expression, kind=kind)
3541
3542    def _parse_historical_data(self) -> t.Optional[exp.HistoricalData]:
3543        # https://docs.snowflake.com/en/sql-reference/constructs/at-before
3544        index = self._index
3545        historical_data = None
3546        if self._match_texts(self.HISTORICAL_DATA_PREFIX):
3547            this = self._prev.text.upper()
3548            kind = (
3549                self._match(TokenType.L_PAREN)
3550                and self._match_texts(self.HISTORICAL_DATA_KIND)
3551                and self._prev.text.upper()
3552            )
3553            expression = self._match(TokenType.FARROW) and self._parse_bitwise()
3554
3555            if expression:
3556                self._match_r_paren()
3557                historical_data = self.expression(
3558                    exp.HistoricalData, this=this, kind=kind, expression=expression
3559                )
3560            else:
3561                self._retreat(index)
3562
3563        return historical_data
3564
3565    def _parse_changes(self) -> t.Optional[exp.Changes]:
3566        if not self._match_text_seq("CHANGES", "(", "INFORMATION", "=>"):
3567            return None
3568
3569        information = self._parse_var(any_token=True)
3570        self._match_r_paren()
3571
3572        return self.expression(
3573            exp.Changes,
3574            information=information,
3575            at_before=self._parse_historical_data(),
3576            end=self._parse_historical_data(),
3577        )
3578
3579    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
3580        if not self._match(TokenType.UNNEST):
3581            return None
3582
3583        expressions = self._parse_wrapped_csv(self._parse_equality)
3584        offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
3585
3586        alias = self._parse_table_alias() if with_alias else None
3587
3588        if alias:
3589            if self.dialect.UNNEST_COLUMN_ONLY:
3590                if alias.args.get("columns"):
3591                    self.raise_error("Unexpected extra column alias in unnest.")
3592
3593                alias.set("columns", [alias.this])
3594                alias.set("this", None)
3595
3596            columns = alias.args.get("columns") or []
3597            if offset and len(expressions) < len(columns):
3598                offset = columns.pop()
3599
3600        if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
3601            self._match(TokenType.ALIAS)
3602            offset = self._parse_id_var(
3603                any_token=False, tokens=self.UNNEST_OFFSET_ALIAS_TOKENS
3604            ) or exp.to_identifier("offset")
3605
3606        return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
3607
3608    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
3609        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
3610        if not is_derived and not self._match_text_seq("VALUES"):
3611            return None
3612
3613        expressions = self._parse_csv(self._parse_value)
3614        alias = self._parse_table_alias()
3615
3616        if is_derived:
3617            self._match_r_paren()
3618
3619        return self.expression(
3620            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
3621        )
3622
3623    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
3624        if not self._match(TokenType.TABLE_SAMPLE) and not (
3625            as_modifier and self._match_text_seq("USING", "SAMPLE")
3626        ):
3627            return None
3628
3629        bucket_numerator = None
3630        bucket_denominator = None
3631        bucket_field = None
3632        percent = None
3633        size = None
3634        seed = None
3635
3636        method = self._parse_var(tokens=(TokenType.ROW,), upper=True)
3637        matched_l_paren = self._match(TokenType.L_PAREN)
3638
3639        if self.TABLESAMPLE_CSV:
3640            num = None
3641            expressions = self._parse_csv(self._parse_primary)
3642        else:
3643            expressions = None
3644            num = (
3645                self._parse_factor()
3646                if self._match(TokenType.NUMBER, advance=False)
3647                else self._parse_primary() or self._parse_placeholder()
3648            )
3649
3650        if self._match_text_seq("BUCKET"):
3651            bucket_numerator = self._parse_number()
3652            self._match_text_seq("OUT", "OF")
3653            bucket_denominator = bucket_denominator = self._parse_number()
3654            self._match(TokenType.ON)
3655            bucket_field = self._parse_field()
3656        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
3657            percent = num
3658        elif self._match(TokenType.ROWS) or not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
3659            size = num
3660        else:
3661            percent = num
3662
3663        if matched_l_paren:
3664            self._match_r_paren()
3665
3666        if self._match(TokenType.L_PAREN):
3667            method = self._parse_var(upper=True)
3668            seed = self._match(TokenType.COMMA) and self._parse_number()
3669            self._match_r_paren()
3670        elif self._match_texts(("SEED", "REPEATABLE")):
3671            seed = self._parse_wrapped(self._parse_number)
3672
3673        if not method and self.DEFAULT_SAMPLING_METHOD:
3674            method = exp.var(self.DEFAULT_SAMPLING_METHOD)
3675
3676        return self.expression(
3677            exp.TableSample,
3678            expressions=expressions,
3679            method=method,
3680            bucket_numerator=bucket_numerator,
3681            bucket_denominator=bucket_denominator,
3682            bucket_field=bucket_field,
3683            percent=percent,
3684            size=size,
3685            seed=seed,
3686        )
3687
3688    def _parse_pivots(self) -> t.Optional[t.List[exp.Pivot]]:
3689        return list(iter(self._parse_pivot, None)) or None
3690
3691    def _parse_joins(self) -> t.Iterator[exp.Join]:
3692        return iter(self._parse_join, None)
3693
3694    # https://duckdb.org/docs/sql/statements/pivot
3695    def _parse_simplified_pivot(self) -> exp.Pivot:
3696        def _parse_on() -> t.Optional[exp.Expression]:
3697            this = self._parse_bitwise()
3698            return self._parse_in(this) if self._match(TokenType.IN) else this
3699
3700        this = self._parse_table()
3701        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
3702        using = self._match(TokenType.USING) and self._parse_csv(
3703            lambda: self._parse_alias(self._parse_function())
3704        )
3705        group = self._parse_group()
3706        return self.expression(
3707            exp.Pivot, this=this, expressions=expressions, using=using, group=group
3708        )
3709
3710    def _parse_pivot_in(self) -> exp.In:
3711        def _parse_aliased_expression() -> t.Optional[exp.Expression]:
3712            this = self._parse_assignment()
3713
3714            self._match(TokenType.ALIAS)
3715            alias = self._parse_field()
3716            if alias:
3717                return self.expression(exp.PivotAlias, this=this, alias=alias)
3718
3719            return this
3720
3721        value = self._parse_column()
3722
3723        if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
3724            self.raise_error("Expecting IN (")
3725
3726        aliased_expressions = self._parse_csv(_parse_aliased_expression)
3727
3728        self._match_r_paren()
3729        return self.expression(exp.In, this=value, expressions=aliased_expressions)
3730
3731    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
3732        index = self._index
3733        include_nulls = None
3734
3735        if self._match(TokenType.PIVOT):
3736            unpivot = False
3737        elif self._match(TokenType.UNPIVOT):
3738            unpivot = True
3739
3740            # https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
3741            if self._match_text_seq("INCLUDE", "NULLS"):
3742                include_nulls = True
3743            elif self._match_text_seq("EXCLUDE", "NULLS"):
3744                include_nulls = False
3745        else:
3746            return None
3747
3748        expressions = []
3749
3750        if not self._match(TokenType.L_PAREN):
3751            self._retreat(index)
3752            return None
3753
3754        if unpivot:
3755            expressions = self._parse_csv(self._parse_column)
3756        else:
3757            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
3758
3759        if not expressions:
3760            self.raise_error("Failed to parse PIVOT's aggregation list")
3761
3762        if not self._match(TokenType.FOR):
3763            self.raise_error("Expecting FOR")
3764
3765        field = self._parse_pivot_in()
3766
3767        self._match_r_paren()
3768
3769        pivot = self.expression(
3770            exp.Pivot,
3771            expressions=expressions,
3772            field=field,
3773            unpivot=unpivot,
3774            include_nulls=include_nulls,
3775        )
3776
3777        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
3778            pivot.set("alias", self._parse_table_alias())
3779
3780        if not unpivot:
3781            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
3782
3783            columns: t.List[exp.Expression] = []
3784            for fld in pivot.args["field"].expressions:
3785                field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
3786                for name in names:
3787                    if self.PREFIXED_PIVOT_COLUMNS:
3788                        name = f"{name}_{field_name}" if name else field_name
3789                    else:
3790                        name = f"{field_name}_{name}" if name else field_name
3791
3792                    columns.append(exp.to_identifier(name))
3793
3794            pivot.set("columns", columns)
3795
3796        return pivot
3797
3798    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
3799        return [agg.alias for agg in aggregations]
3800
3801    def _parse_prewhere(self, skip_where_token: bool = False) -> t.Optional[exp.PreWhere]:
3802        if not skip_where_token and not self._match(TokenType.PREWHERE):
3803            return None
3804
3805        return self.expression(
3806            exp.PreWhere, comments=self._prev_comments, this=self._parse_assignment()
3807        )
3808
3809    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
3810        if not skip_where_token and not self._match(TokenType.WHERE):
3811            return None
3812
3813        return self.expression(
3814            exp.Where, comments=self._prev_comments, this=self._parse_assignment()
3815        )
3816
3817    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
3818        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
3819            return None
3820
3821        elements: t.Dict[str, t.Any] = defaultdict(list)
3822
3823        if self._match(TokenType.ALL):
3824            elements["all"] = True
3825        elif self._match(TokenType.DISTINCT):
3826            elements["all"] = False
3827
3828        while True:
3829            expressions = self._parse_csv(
3830                lambda: None
3831                if self._match_set((TokenType.CUBE, TokenType.ROLLUP), advance=False)
3832                else self._parse_assignment()
3833            )
3834            if expressions:
3835                elements["expressions"].extend(expressions)
3836
3837            grouping_sets = self._parse_grouping_sets()
3838            if grouping_sets:
3839                elements["grouping_sets"].extend(grouping_sets)
3840
3841            rollup = None
3842            cube = None
3843            totals = None
3844
3845            index = self._index
3846            with_ = self._match(TokenType.WITH)
3847            if self._match(TokenType.ROLLUP):
3848                rollup = with_ or self._parse_wrapped_csv(self._parse_column)
3849                elements["rollup"].extend(ensure_list(rollup))
3850
3851            if self._match(TokenType.CUBE):
3852                cube = with_ or self._parse_wrapped_csv(self._parse_column)
3853                elements["cube"].extend(ensure_list(cube))
3854
3855            if self._match_text_seq("TOTALS"):
3856                totals = True
3857                elements["totals"] = True  # type: ignore
3858
3859            if not (grouping_sets or rollup or cube or totals):
3860                if with_:
3861                    self._retreat(index)
3862                break
3863
3864        return self.expression(exp.Group, **elements)  # type: ignore
3865
3866    def _parse_grouping_sets(self) -> t.Optional[t.List[exp.Expression]]:
3867        if not self._match(TokenType.GROUPING_SETS):
3868            return None
3869
3870        return self._parse_wrapped_csv(self._parse_grouping_set)
3871
3872    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
3873        if self._match(TokenType.L_PAREN):
3874            grouping_set = self._parse_csv(self._parse_column)
3875            self._match_r_paren()
3876            return self.expression(exp.Tuple, expressions=grouping_set)
3877
3878        return self._parse_column()
3879
3880    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
3881        if not skip_having_token and not self._match(TokenType.HAVING):
3882            return None
3883        return self.expression(exp.Having, this=self._parse_assignment())
3884
3885    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
3886        if not self._match(TokenType.QUALIFY):
3887            return None
3888        return self.expression(exp.Qualify, this=self._parse_assignment())
3889
3890    def _parse_connect(self, skip_start_token: bool = False) -> t.Optional[exp.Connect]:
3891        if skip_start_token:
3892            start = None
3893        elif self._match(TokenType.START_WITH):
3894            start = self._parse_assignment()
3895        else:
3896            return None
3897
3898        self._match(TokenType.CONNECT_BY)
3899        nocycle = self._match_text_seq("NOCYCLE")
3900        self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
3901            exp.Prior, this=self._parse_bitwise()
3902        )
3903        connect = self._parse_assignment()
3904        self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
3905
3906        if not start and self._match(TokenType.START_WITH):
3907            start = self._parse_assignment()
3908
3909        return self.expression(exp.Connect, start=start, connect=connect, nocycle=nocycle)
3910
3911    def _parse_name_as_expression(self) -> exp.Alias:
3912        return self.expression(
3913            exp.Alias,
3914            alias=self._parse_id_var(any_token=True),
3915            this=self._match(TokenType.ALIAS) and self._parse_assignment(),
3916        )
3917
3918    def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
3919        if self._match_text_seq("INTERPOLATE"):
3920            return self._parse_wrapped_csv(self._parse_name_as_expression)
3921        return None
3922
3923    def _parse_order(
3924        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
3925    ) -> t.Optional[exp.Expression]:
3926        siblings = None
3927        if not skip_order_token and not self._match(TokenType.ORDER_BY):
3928            if not self._match(TokenType.ORDER_SIBLINGS_BY):
3929                return this
3930
3931            siblings = True
3932
3933        return self.expression(
3934            exp.Order,
3935            this=this,
3936            expressions=self._parse_csv(self._parse_ordered),
3937            interpolate=self._parse_interpolate(),
3938            siblings=siblings,
3939        )
3940
3941    def _parse_sort(self, exp_class: t.Type[E], token: TokenType) -> t.Optional[E]:
3942        if not self._match(token):
3943            return None
3944        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
3945
3946    def _parse_ordered(
3947        self, parse_method: t.Optional[t.Callable] = None
3948    ) -> t.Optional[exp.Ordered]:
3949        this = parse_method() if parse_method else self._parse_assignment()
3950        if not this:
3951            return None
3952
3953        if this.name.upper() == "ALL" and self.dialect.SUPPORTS_ORDER_BY_ALL:
3954            this = exp.var("ALL")
3955
3956        asc = self._match(TokenType.ASC)
3957        desc = self._match(TokenType.DESC) or (asc and False)
3958
3959        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
3960        is_nulls_last = self._match_text_seq("NULLS", "LAST")
3961
3962        nulls_first = is_nulls_first or False
3963        explicitly_null_ordered = is_nulls_first or is_nulls_last
3964
3965        if (
3966            not explicitly_null_ordered
3967            and (
3968                (not desc and self.dialect.NULL_ORDERING == "nulls_are_small")
3969                or (desc and self.dialect.NULL_ORDERING != "nulls_are_small")
3970            )
3971            and self.dialect.NULL_ORDERING != "nulls_are_last"
3972        ):
3973            nulls_first = True
3974
3975        if self._match_text_seq("WITH", "FILL"):
3976            with_fill = self.expression(
3977                exp.WithFill,
3978                **{  # type: ignore
3979                    "from": self._match(TokenType.FROM) and self._parse_bitwise(),
3980                    "to": self._match_text_seq("TO") and self._parse_bitwise(),
3981                    "step": self._match_text_seq("STEP") and self._parse_bitwise(),
3982                },
3983            )
3984        else:
3985            with_fill = None
3986
3987        return self.expression(
3988            exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
3989        )
3990
3991    def _parse_limit(
3992        self,
3993        this: t.Optional[exp.Expression] = None,
3994        top: bool = False,
3995        skip_limit_token: bool = False,
3996    ) -> t.Optional[exp.Expression]:
3997        if skip_limit_token or self._match(TokenType.TOP if top else TokenType.LIMIT):
3998            comments = self._prev_comments
3999            if top:
4000                limit_paren = self._match(TokenType.L_PAREN)
4001                expression = self._parse_term() if limit_paren else self._parse_number()
4002
4003                if limit_paren:
4004                    self._match_r_paren()
4005            else:
4006                expression = self._parse_term()
4007
4008            if self._match(TokenType.COMMA):
4009                offset = expression
4010                expression = self._parse_term()
4011            else:
4012                offset = None
4013
4014            limit_exp = self.expression(
4015                exp.Limit,
4016                this=this,
4017                expression=expression,
4018                offset=offset,
4019                comments=comments,
4020                expressions=self._parse_limit_by(),
4021            )
4022
4023            return limit_exp
4024
4025        if self._match(TokenType.FETCH):
4026            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
4027            direction = self._prev.text.upper() if direction else "FIRST"
4028
4029            count = self._parse_field(tokens=self.FETCH_TOKENS)
4030            percent = self._match(TokenType.PERCENT)
4031
4032            self._match_set((TokenType.ROW, TokenType.ROWS))
4033
4034            only = self._match_text_seq("ONLY")
4035            with_ties = self._match_text_seq("WITH", "TIES")
4036
4037            if only and with_ties:
4038                self.raise_error("Cannot specify both ONLY and WITH TIES in FETCH clause")
4039
4040            return self.expression(
4041                exp.Fetch,
4042                direction=direction,
4043                count=count,
4044                percent=percent,
4045                with_ties=with_ties,
4046            )
4047
4048        return this
4049
4050    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4051        if not self._match(TokenType.OFFSET):
4052            return this
4053
4054        count = self._parse_term()
4055        self._match_set((TokenType.ROW, TokenType.ROWS))
4056
4057        return self.expression(
4058            exp.Offset, this=this, expression=count, expressions=self._parse_limit_by()
4059        )
4060
4061    def _parse_limit_by(self) -> t.Optional[t.List[exp.Expression]]:
4062        return self._match_text_seq("BY") and self._parse_csv(self._parse_bitwise)
4063
4064    def _parse_locks(self) -> t.List[exp.Lock]:
4065        locks = []
4066        while True:
4067            if self._match_text_seq("FOR", "UPDATE"):
4068                update = True
4069            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
4070                "LOCK", "IN", "SHARE", "MODE"
4071            ):
4072                update = False
4073            else:
4074                break
4075
4076            expressions = None
4077            if self._match_text_seq("OF"):
4078                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
4079
4080            wait: t.Optional[bool | exp.Expression] = None
4081            if self._match_text_seq("NOWAIT"):
4082                wait = True
4083            elif self._match_text_seq("WAIT"):
4084                wait = self._parse_primary()
4085            elif self._match_text_seq("SKIP", "LOCKED"):
4086                wait = False
4087
4088            locks.append(
4089                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
4090            )
4091
4092        return locks
4093
4094    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4095        while this and self._match_set(self.SET_OPERATIONS):
4096            token_type = self._prev.token_type
4097
4098            if token_type == TokenType.UNION:
4099                operation: t.Type[exp.SetOperation] = exp.Union
4100            elif token_type == TokenType.EXCEPT:
4101                operation = exp.Except
4102            else:
4103                operation = exp.Intersect
4104
4105            comments = self._prev.comments
4106            distinct = self._match(TokenType.DISTINCT) or not self._match(TokenType.ALL)
4107            by_name = self._match_text_seq("BY", "NAME")
4108            expression = self._parse_select(nested=True, parse_set_operation=False)
4109
4110            this = self.expression(
4111                operation,
4112                comments=comments,
4113                this=this,
4114                distinct=distinct,
4115                by_name=by_name,
4116                expression=expression,
4117            )
4118
4119        if isinstance(this, exp.SetOperation) and self.MODIFIERS_ATTACHED_TO_SET_OP:
4120            expression = this.expression
4121
4122            if expression:
4123                for arg in self.SET_OP_MODIFIERS:
4124                    expr = expression.args.get(arg)
4125                    if expr:
4126                        this.set(arg, expr.pop())
4127
4128        return this
4129
4130    def _parse_expression(self) -> t.Optional[exp.Expression]:
4131        return self._parse_alias(self._parse_assignment())
4132
4133    def _parse_assignment(self) -> t.Optional[exp.Expression]:
4134        this = self._parse_disjunction()
4135
4136        while self._match_set(self.ASSIGNMENT):
4137            this = self.expression(
4138                self.ASSIGNMENT[self._prev.token_type],
4139                this=this,
4140                comments=self._prev_comments,
4141                expression=self._parse_assignment(),
4142            )
4143
4144        return this
4145
4146    def _parse_disjunction(self) -> t.Optional[exp.Expression]:
4147        return self._parse_tokens(self._parse_conjunction, self.DISJUNCTION)
4148
4149    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
4150        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
4151
4152    def _parse_equality(self) -> t.Optional[exp.Expression]:
4153        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
4154
4155    def _parse_comparison(self) -> t.Optional[exp.Expression]:
4156        return self._parse_tokens(self._parse_range, self.COMPARISON)
4157
4158    def _parse_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4159        this = this or self._parse_bitwise()
4160        negate = self._match(TokenType.NOT)
4161
4162        if self._match_set(self.RANGE_PARSERS):
4163            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
4164            if not expression:
4165                return this
4166
4167            this = expression
4168        elif self._match(TokenType.ISNULL):
4169            this = self.expression(exp.Is, this=this, expression=exp.Null())
4170
4171        # Postgres supports ISNULL and NOTNULL for conditions.
4172        # https://blog.andreiavram.ro/postgresql-null-composite-type/
4173        if self._match(TokenType.NOTNULL):
4174            this = self.expression(exp.Is, this=this, expression=exp.Null())
4175            this = self.expression(exp.Not, this=this)
4176
4177        if negate:
4178            this = self.expression(exp.Not, this=this)
4179
4180        if self._match(TokenType.IS):
4181            this = self._parse_is(this)
4182
4183        return this
4184
4185    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4186        index = self._index - 1
4187        negate = self._match(TokenType.NOT)
4188
4189        if self._match_text_seq("DISTINCT", "FROM"):
4190            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
4191            return self.expression(klass, this=this, expression=self._parse_bitwise())
4192
4193        expression = self._parse_null() or self._parse_boolean()
4194        if not expression:
4195            self._retreat(index)
4196            return None
4197
4198        this = self.expression(exp.Is, this=this, expression=expression)
4199        return self.expression(exp.Not, this=this) if negate else this
4200
4201    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
4202        unnest = self._parse_unnest(with_alias=False)
4203        if unnest:
4204            this = self.expression(exp.In, this=this, unnest=unnest)
4205        elif self._match_set((TokenType.L_PAREN, TokenType.L_BRACKET)):
4206            matched_l_paren = self._prev.token_type == TokenType.L_PAREN
4207            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
4208
4209            if len(expressions) == 1 and isinstance(expressions[0], exp.Query):
4210                this = self.expression(exp.In, this=this, query=expressions[0].subquery(copy=False))
4211            else:
4212                this = self.expression(exp.In, this=this, expressions=expressions)
4213
4214            if matched_l_paren:
4215                self._match_r_paren(this)
4216            elif not self._match(TokenType.R_BRACKET, expression=this):
4217                self.raise_error("Expecting ]")
4218        else:
4219            this = self.expression(exp.In, this=this, field=self._parse_field())
4220
4221        return this
4222
4223    def _parse_between(self, this: t.Optional[exp.Expression]) -> exp.Between:
4224        low = self._parse_bitwise()
4225        self._match(TokenType.AND)
4226        high = self._parse_bitwise()
4227        return self.expression(exp.Between, this=this, low=low, high=high)
4228
4229    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4230        if not self._match(TokenType.ESCAPE):
4231            return this
4232        return self.expression(exp.Escape, this=this, expression=self._parse_string())
4233
4234    def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Add | exp.Interval]:
4235        index = self._index
4236
4237        if not self._match(TokenType.INTERVAL) and match_interval:
4238            return None
4239
4240        if self._match(TokenType.STRING, advance=False):
4241            this = self._parse_primary()
4242        else:
4243            this = self._parse_term()
4244
4245        if not this or (
4246            isinstance(this, exp.Column)
4247            and not this.table
4248            and not this.this.quoted
4249            and this.name.upper() == "IS"
4250        ):
4251            self._retreat(index)
4252            return None
4253
4254        unit = self._parse_function() or (
4255            not self._match(TokenType.ALIAS, advance=False)
4256            and self._parse_var(any_token=True, upper=True)
4257        )
4258
4259        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
4260        # each INTERVAL expression into this canonical form so it's easy to transpile
4261        if this and this.is_number:
4262            this = exp.Literal.string(this.to_py())
4263        elif this and this.is_string:
4264            parts = exp.INTERVAL_STRING_RE.findall(this.name)
4265            if len(parts) == 1:
4266                if unit:
4267                    # Unconsume the eagerly-parsed unit, since the real unit was part of the string
4268                    self._retreat(self._index - 1)
4269
4270                this = exp.Literal.string(parts[0][0])
4271                unit = self.expression(exp.Var, this=parts[0][1].upper())
4272
4273        if self.INTERVAL_SPANS and self._match_text_seq("TO"):
4274            unit = self.expression(
4275                exp.IntervalSpan, this=unit, expression=self._parse_var(any_token=True, upper=True)
4276            )
4277
4278        interval = self.expression(exp.Interval, this=this, unit=unit)
4279
4280        index = self._index
4281        self._match(TokenType.PLUS)
4282
4283        # Convert INTERVAL 'val_1' unit_1 [+] ... [+] 'val_n' unit_n into a sum of intervals
4284        if self._match_set((TokenType.STRING, TokenType.NUMBER), advance=False):
4285            return self.expression(
4286                exp.Add, this=interval, expression=self._parse_interval(match_interval=False)
4287            )
4288
4289        self._retreat(index)
4290        return interval
4291
4292    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
4293        this = self._parse_term()
4294
4295        while True:
4296            if self._match_set(self.BITWISE):
4297                this = self.expression(
4298                    self.BITWISE[self._prev.token_type],
4299                    this=this,
4300                    expression=self._parse_term(),
4301                )
4302            elif self.dialect.DPIPE_IS_STRING_CONCAT and self._match(TokenType.DPIPE):
4303                this = self.expression(
4304                    exp.DPipe,
4305                    this=this,
4306                    expression=self._parse_term(),
4307                    safe=not self.dialect.STRICT_STRING_CONCAT,
4308                )
4309            elif self._match(TokenType.DQMARK):
4310                this = self.expression(exp.Coalesce, this=this, expressions=self._parse_term())
4311            elif self._match_pair(TokenType.LT, TokenType.LT):
4312                this = self.expression(
4313                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
4314                )
4315            elif self._match_pair(TokenType.GT, TokenType.GT):
4316                this = self.expression(
4317                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
4318                )
4319            else:
4320                break
4321
4322        return this
4323
4324    def _parse_term(self) -> t.Optional[exp.Expression]:
4325        return self._parse_tokens(self._parse_factor, self.TERM)
4326
4327    def _parse_factor(self) -> t.Optional[exp.Expression]:
4328        parse_method = self._parse_exponent if self.EXPONENT else self._parse_unary
4329        this = parse_method()
4330
4331        while self._match_set(self.FACTOR):
4332            klass = self.FACTOR[self._prev.token_type]
4333            comments = self._prev_comments
4334            expression = parse_method()
4335
4336            if not expression and klass is exp.IntDiv and self._prev.text.isalpha():
4337                self._retreat(self._index - 1)
4338                return this
4339
4340            this = self.expression(klass, this=this, comments=comments, expression=expression)
4341
4342            if isinstance(this, exp.Div):
4343                this.args["typed"] = self.dialect.TYPED_DIVISION
4344                this.args["safe"] = self.dialect.SAFE_DIVISION
4345
4346        return this
4347
4348    def _parse_exponent(self) -> t.Optional[exp.Expression]:
4349        return self._parse_tokens(self._parse_unary, self.EXPONENT)
4350
4351    def _parse_unary(self) -> t.Optional[exp.Expression]:
4352        if self._match_set(self.UNARY_PARSERS):
4353            return self.UNARY_PARSERS[self._prev.token_type](self)
4354        return self._parse_at_time_zone(self._parse_type())
4355
4356    def _parse_type(
4357        self, parse_interval: bool = True, fallback_to_identifier: bool = False
4358    ) -> t.Optional[exp.Expression]:
4359        interval = parse_interval and self._parse_interval()
4360        if interval:
4361            return interval
4362
4363        index = self._index
4364        data_type = self._parse_types(check_func=True, allow_identifiers=False)
4365
4366        # parse_types() returns a Cast if we parsed BQ's inline constructor <type>(<values>) e.g.
4367        # STRUCT<a INT, b STRING>(1, 'foo'), which is canonicalized to CAST(<values> AS <type>)
4368        if isinstance(data_type, exp.Cast):
4369            # This constructor can contain ops directly after it, for instance struct unnesting:
4370            # STRUCT<a INT, b STRING>(1, 'foo').* --> CAST(STRUCT(1, 'foo') AS STRUCT<a iNT, b STRING).*
4371            return self._parse_column_ops(data_type)
4372
4373        if data_type:
4374            index2 = self._index
4375            this = self._parse_primary()
4376
4377            if isinstance(this, exp.Literal):
4378                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
4379                if parser:
4380                    return parser(self, this, data_type)
4381
4382                return self.expression(exp.Cast, this=this, to=data_type)
4383
4384            # The expressions arg gets set by the parser when we have something like DECIMAL(38, 0)
4385            # in the input SQL. In that case, we'll produce these tokens: DECIMAL ( 38 , 0 )
4386            #
4387            # If the index difference here is greater than 1, that means the parser itself must have
4388            # consumed additional tokens such as the DECIMAL scale and precision in the above example.
4389            #
4390            # If it's not greater than 1, then it must be 1, because we've consumed at least the type
4391            # keyword, meaning that the expressions arg of the DataType must have gotten set by a
4392            # callable in the TYPE_CONVERTERS mapping. For example, Snowflake converts DECIMAL to
4393            # DECIMAL(38, 0)) in order to facilitate the data type's transpilation.
4394            #
4395            # In these cases, we don't really want to return the converted type, but instead retreat
4396            # and try to parse a Column or Identifier in the section below.
4397            if data_type.expressions and index2 - index > 1:
4398                self._retreat(index2)
4399                return self._parse_column_ops(data_type)
4400
4401            self._retreat(index)
4402
4403        if fallback_to_identifier:
4404            return self._parse_id_var()
4405
4406        this = self._parse_column()
4407        return this and self._parse_column_ops(this)
4408
4409    def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
4410        this = self._parse_type()
4411        if not this:
4412            return None
4413
4414        if isinstance(this, exp.Column) and not this.table:
4415            this = exp.var(this.name.upper())
4416
4417        return self.expression(
4418            exp.DataTypeParam, this=this, expression=self._parse_var(any_token=True)
4419        )
4420
4421    def _parse_types(
4422        self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
4423    ) -> t.Optional[exp.Expression]:
4424        index = self._index
4425
4426        this: t.Optional[exp.Expression] = None
4427        prefix = self._match_text_seq("SYSUDTLIB", ".")
4428
4429        if not self._match_set(self.TYPE_TOKENS):
4430            identifier = allow_identifiers and self._parse_id_var(
4431                any_token=False, tokens=(TokenType.VAR,)
4432            )
4433            if isinstance(identifier, exp.Identifier):
4434                tokens = self.dialect.tokenize(identifier.sql(dialect=self.dialect))
4435
4436                if len(tokens) != 1:
4437                    self.raise_error("Unexpected identifier", self._prev)
4438
4439                if tokens[0].token_type in self.TYPE_TOKENS:
4440                    self._prev = tokens[0]
4441                elif self.dialect.SUPPORTS_USER_DEFINED_TYPES:
4442                    type_name = identifier.name
4443
4444                    while self._match(TokenType.DOT):
4445                        type_name = f"{type_name}.{self._advance_any() and self._prev.text}"
4446
4447                    this = exp.DataType.build(type_name, udt=True)
4448                else:
4449                    self._retreat(self._index - 1)
4450                    return None
4451            else:
4452                return None
4453
4454        type_token = self._prev.token_type
4455
4456        if type_token == TokenType.PSEUDO_TYPE:
4457            return self.expression(exp.PseudoType, this=self._prev.text.upper())
4458
4459        if type_token == TokenType.OBJECT_IDENTIFIER:
4460            return self.expression(exp.ObjectIdentifier, this=self._prev.text.upper())
4461
4462        # https://materialize.com/docs/sql/types/map/
4463        if type_token == TokenType.MAP and self._match(TokenType.L_BRACKET):
4464            key_type = self._parse_types(
4465                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4466            )
4467            if not self._match(TokenType.FARROW):
4468                self._retreat(index)
4469                return None
4470
4471            value_type = self._parse_types(
4472                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4473            )
4474            if not self._match(TokenType.R_BRACKET):
4475                self._retreat(index)
4476                return None
4477
4478            return exp.DataType(
4479                this=exp.DataType.Type.MAP,
4480                expressions=[key_type, value_type],
4481                nested=True,
4482                prefix=prefix,
4483            )
4484
4485        nested = type_token in self.NESTED_TYPE_TOKENS
4486        is_struct = type_token in self.STRUCT_TYPE_TOKENS
4487        is_aggregate = type_token in self.AGGREGATE_TYPE_TOKENS
4488        expressions = None
4489        maybe_func = False
4490
4491        if self._match(TokenType.L_PAREN):
4492            if is_struct:
4493                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
4494            elif nested:
4495                expressions = self._parse_csv(
4496                    lambda: self._parse_types(
4497                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4498                    )
4499                )
4500            elif type_token in self.ENUM_TYPE_TOKENS:
4501                expressions = self._parse_csv(self._parse_equality)
4502            elif is_aggregate:
4503                func_or_ident = self._parse_function(anonymous=True) or self._parse_id_var(
4504                    any_token=False, tokens=(TokenType.VAR,)
4505                )
4506                if not func_or_ident or not self._match(TokenType.COMMA):
4507                    return None
4508                expressions = self._parse_csv(
4509                    lambda: self._parse_types(
4510                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4511                    )
4512                )
4513                expressions.insert(0, func_or_ident)
4514            else:
4515                expressions = self._parse_csv(self._parse_type_size)
4516
4517                # https://docs.snowflake.com/en/sql-reference/data-types-vector
4518                if type_token == TokenType.VECTOR and len(expressions) == 2:
4519                    expressions[0] = exp.DataType.build(expressions[0].name, dialect=self.dialect)
4520
4521            if not expressions or not self._match(TokenType.R_PAREN):
4522                self._retreat(index)
4523                return None
4524
4525            maybe_func = True
4526
4527        values: t.Optional[t.List[exp.Expression]] = None
4528
4529        if nested and self._match(TokenType.LT):
4530            if is_struct:
4531                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
4532            else:
4533                expressions = self._parse_csv(
4534                    lambda: self._parse_types(
4535                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4536                    )
4537                )
4538
4539            if not self._match(TokenType.GT):
4540                self.raise_error("Expecting >")
4541
4542            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
4543                values = self._parse_csv(self._parse_assignment)
4544                self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
4545
4546        if type_token in self.TIMESTAMPS:
4547            if self._match_text_seq("WITH", "TIME", "ZONE"):
4548                maybe_func = False
4549                tz_type = (
4550                    exp.DataType.Type.TIMETZ
4551                    if type_token in self.TIMES
4552                    else exp.DataType.Type.TIMESTAMPTZ
4553                )
4554                this = exp.DataType(this=tz_type, expressions=expressions)
4555            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
4556                maybe_func = False
4557                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
4558            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
4559                maybe_func = False
4560        elif type_token == TokenType.INTERVAL:
4561            unit = self._parse_var(upper=True)
4562            if unit:
4563                if self._match_text_seq("TO"):
4564                    unit = exp.IntervalSpan(this=unit, expression=self._parse_var(upper=True))
4565
4566                this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
4567            else:
4568                this = self.expression(exp.DataType, this=exp.DataType.Type.INTERVAL)
4569
4570        if maybe_func and check_func:
4571            index2 = self._index
4572            peek = self._parse_string()
4573
4574            if not peek:
4575                self._retreat(index)
4576                return None
4577
4578            self._retreat(index2)
4579
4580        if not this:
4581            if self._match_text_seq("UNSIGNED"):
4582                unsigned_type_token = self.SIGNED_TO_UNSIGNED_TYPE_TOKEN.get(type_token)
4583                if not unsigned_type_token:
4584                    self.raise_error(f"Cannot convert {type_token.value} to unsigned.")
4585
4586                type_token = unsigned_type_token or type_token
4587
4588            this = exp.DataType(
4589                this=exp.DataType.Type[type_token.value],
4590                expressions=expressions,
4591                nested=nested,
4592                prefix=prefix,
4593            )
4594
4595            # Empty arrays/structs are allowed
4596            if values is not None:
4597                cls = exp.Struct if is_struct else exp.Array
4598                this = exp.cast(cls(expressions=values), this, copy=False)
4599
4600        elif expressions:
4601            this.set("expressions", expressions)
4602
4603        # https://materialize.com/docs/sql/types/list/#type-name
4604        while self._match(TokenType.LIST):
4605            this = exp.DataType(this=exp.DataType.Type.LIST, expressions=[this], nested=True)
4606
4607        index = self._index
4608
4609        # Postgres supports the INT ARRAY[3] syntax as a synonym for INT[3]
4610        matched_array = self._match(TokenType.ARRAY)
4611
4612        while self._curr:
4613            matched_l_bracket = self._match(TokenType.L_BRACKET)
4614            if not matched_l_bracket and not matched_array:
4615                break
4616
4617            matched_array = False
4618            values = self._parse_csv(self._parse_assignment) or None
4619            if (
4620                values
4621                and not schema
4622                and this.is_type(exp.DataType.Type.ARRAY, exp.DataType.Type.MAP)
4623            ):
4624                self._retreat(index)
4625                break
4626
4627            this = exp.DataType(
4628                this=exp.DataType.Type.ARRAY, expressions=[this], values=values, nested=True
4629            )
4630            self._match(TokenType.R_BRACKET)
4631
4632        if self.TYPE_CONVERTERS and isinstance(this.this, exp.DataType.Type):
4633            converter = self.TYPE_CONVERTERS.get(this.this)
4634            if converter:
4635                this = converter(t.cast(exp.DataType, this))
4636
4637        return this
4638
4639    def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
4640        index = self._index
4641
4642        if (
4643            self._curr
4644            and self._next
4645            and self._curr.token_type in self.TYPE_TOKENS
4646            and self._next.token_type in self.TYPE_TOKENS
4647        ):
4648            # Takes care of special cases like `STRUCT<list ARRAY<...>>` where the identifier is also a
4649            # type token. Without this, the list will be parsed as a type and we'll eventually crash
4650            this = self._parse_id_var()
4651        else:
4652            this = (
4653                self._parse_type(parse_interval=False, fallback_to_identifier=True)
4654                or self._parse_id_var()
4655            )
4656
4657        self._match(TokenType.COLON)
4658
4659        if (
4660            type_required
4661            and not isinstance(this, exp.DataType)
4662            and not self._match_set(self.TYPE_TOKENS, advance=False)
4663        ):
4664            self._retreat(index)
4665            return self._parse_types()
4666
4667        return self._parse_column_def(this)
4668
4669    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4670        if not self._match_text_seq("AT", "TIME", "ZONE"):
4671            return this
4672        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
4673
4674    def _parse_column(self) -> t.Optional[exp.Expression]:
4675        this = self._parse_column_reference()
4676        column = self._parse_column_ops(this) if this else self._parse_bracket(this)
4677
4678        if self.dialect.SUPPORTS_COLUMN_JOIN_MARKS and column:
4679            column.set("join_mark", self._match(TokenType.JOIN_MARKER))
4680
4681        return column
4682
4683    def _parse_column_reference(self) -> t.Optional[exp.Expression]:
4684        this = self._parse_field()
4685        if (
4686            not this
4687            and self._match(TokenType.VALUES, advance=False)
4688            and self.VALUES_FOLLOWED_BY_PAREN
4689            and (not self._next or self._next.token_type != TokenType.L_PAREN)
4690        ):
4691            this = self._parse_id_var()
4692
4693        if isinstance(this, exp.Identifier):
4694            # We bubble up comments from the Identifier to the Column
4695            this = self.expression(exp.Column, comments=this.pop_comments(), this=this)
4696
4697        return this
4698
4699    def _parse_colon_as_variant_extract(
4700        self, this: t.Optional[exp.Expression]
4701    ) -> t.Optional[exp.Expression]:
4702        casts = []
4703        json_path = []
4704
4705        while self._match(TokenType.COLON):
4706            start_index = self._index
4707
4708            # Snowflake allows reserved keywords as json keys but advance_any() excludes TokenType.SELECT from any_tokens=True
4709            path = self._parse_column_ops(
4710                self._parse_field(any_token=True, tokens=(TokenType.SELECT,))
4711            )
4712
4713            # The cast :: operator has a lower precedence than the extraction operator :, so
4714            # we rearrange the AST appropriately to avoid casting the JSON path
4715            while isinstance(path, exp.Cast):
4716                casts.append(path.to)
4717                path = path.this
4718
4719            if casts:
4720                dcolon_offset = next(
4721                    i
4722                    for i, t in enumerate(self._tokens[start_index:])
4723                    if t.token_type == TokenType.DCOLON
4724                )
4725                end_token = self._tokens[start_index + dcolon_offset - 1]
4726            else:
4727                end_token = self._prev
4728
4729            if path:
4730                json_path.append(self._find_sql(self._tokens[start_index], end_token))
4731
4732        # The VARIANT extract in Snowflake/Databricks is parsed as a JSONExtract; Snowflake uses the json_path in GET_PATH() while
4733        # Databricks transforms it back to the colon/dot notation
4734        if json_path:
4735            this = self.expression(
4736                exp.JSONExtract,
4737                this=this,
4738                expression=self.dialect.to_json_path(exp.Literal.string(".".join(json_path))),
4739                variant_extract=True,
4740            )
4741
4742            while casts:
4743                this = self.expression(exp.Cast, this=this, to=casts.pop())
4744
4745        return this
4746
4747    def _parse_dcolon(self) -> t.Optional[exp.Expression]:
4748        return self._parse_types()
4749
4750    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4751        this = self._parse_bracket(this)
4752
4753        while self._match_set(self.COLUMN_OPERATORS):
4754            op_token = self._prev.token_type
4755            op = self.COLUMN_OPERATORS.get(op_token)
4756
4757            if op_token == TokenType.DCOLON:
4758                field = self._parse_dcolon()
4759                if not field:
4760                    self.raise_error("Expected type")
4761            elif op and self._curr:
4762                field = self._parse_column_reference()
4763            else:
4764                field = self._parse_field(any_token=True, anonymous_func=True)
4765
4766            if isinstance(field, exp.Func) and this:
4767                # bigquery allows function calls like x.y.count(...)
4768                # SAFE.SUBSTR(...)
4769                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
4770                this = exp.replace_tree(
4771                    this,
4772                    lambda n: (
4773                        self.expression(exp.Dot, this=n.args.get("table"), expression=n.this)
4774                        if n.table
4775                        else n.this
4776                    )
4777                    if isinstance(n, exp.Column)
4778                    else n,
4779                )
4780
4781            if op:
4782                this = op(self, this, field)
4783            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
4784                this = self.expression(
4785                    exp.Column,
4786                    this=field,
4787                    table=this.this,
4788                    db=this.args.get("table"),
4789                    catalog=this.args.get("db"),
4790                )
4791            else:
4792                this = self.expression(exp.Dot, this=this, expression=field)
4793
4794            this = self._parse_bracket(this)
4795
4796        return self._parse_colon_as_variant_extract(this) if self.COLON_IS_VARIANT_EXTRACT else this
4797
4798    def _parse_primary(self) -> t.Optional[exp.Expression]:
4799        if self._match_set(self.PRIMARY_PARSERS):
4800            token_type = self._prev.token_type
4801            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
4802
4803            if token_type == TokenType.STRING:
4804                expressions = [primary]
4805                while self._match(TokenType.STRING):
4806                    expressions.append(exp.Literal.string(self._prev.text))
4807
4808                if len(expressions) > 1:
4809                    return self.expression(exp.Concat, expressions=expressions)
4810
4811            return primary
4812
4813        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
4814            return exp.Literal.number(f"0.{self._prev.text}")
4815
4816        if self._match(TokenType.L_PAREN):
4817            comments = self._prev_comments
4818            query = self._parse_select()
4819
4820            if query:
4821                expressions = [query]
4822            else:
4823                expressions = self._parse_expressions()
4824
4825            this = self._parse_query_modifiers(seq_get(expressions, 0))
4826
4827            if not this and self._match(TokenType.R_PAREN, advance=False):
4828                this = self.expression(exp.Tuple)
4829            elif isinstance(this, exp.UNWRAPPED_QUERIES):
4830                this = self._parse_subquery(this=this, parse_alias=False)
4831            elif isinstance(this, exp.Subquery):
4832                this = self._parse_subquery(
4833                    this=self._parse_set_operations(this), parse_alias=False
4834                )
4835            elif len(expressions) > 1 or self._prev.token_type == TokenType.COMMA:
4836                this = self.expression(exp.Tuple, expressions=expressions)
4837            else:
4838                this = self.expression(exp.Paren, this=this)
4839
4840            if this:
4841                this.add_comments(comments)
4842
4843            self._match_r_paren(expression=this)
4844            return this
4845
4846        return None
4847
4848    def _parse_field(
4849        self,
4850        any_token: bool = False,
4851        tokens: t.Optional[t.Collection[TokenType]] = None,
4852        anonymous_func: bool = False,
4853    ) -> t.Optional[exp.Expression]:
4854        if anonymous_func:
4855            field = (
4856                self._parse_function(anonymous=anonymous_func, any_token=any_token)
4857                or self._parse_primary()
4858            )
4859        else:
4860            field = self._parse_primary() or self._parse_function(
4861                anonymous=anonymous_func, any_token=any_token
4862            )
4863        return field or self._parse_id_var(any_token=any_token, tokens=tokens)
4864
4865    def _parse_function(
4866        self,
4867        functions: t.Optional[t.Dict[str, t.Callable]] = None,
4868        anonymous: bool = False,
4869        optional_parens: bool = True,
4870        any_token: bool = False,
4871    ) -> t.Optional[exp.Expression]:
4872        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
4873        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
4874        fn_syntax = False
4875        if (
4876            self._match(TokenType.L_BRACE, advance=False)
4877            and self._next
4878            and self._next.text.upper() == "FN"
4879        ):
4880            self._advance(2)
4881            fn_syntax = True
4882
4883        func = self._parse_function_call(
4884            functions=functions,
4885            anonymous=anonymous,
4886            optional_parens=optional_parens,
4887            any_token=any_token,
4888        )
4889
4890        if fn_syntax:
4891            self._match(TokenType.R_BRACE)
4892
4893        return func
4894
4895    def _parse_function_call(
4896        self,
4897        functions: t.Optional[t.Dict[str, t.Callable]] = None,
4898        anonymous: bool = False,
4899        optional_parens: bool = True,
4900        any_token: bool = False,
4901    ) -> t.Optional[exp.Expression]:
4902        if not self._curr:
4903            return None
4904
4905        comments = self._curr.comments
4906        token_type = self._curr.token_type
4907        this = self._curr.text
4908        upper = this.upper()
4909
4910        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
4911        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
4912            self._advance()
4913            return self._parse_window(parser(self))
4914
4915        if not self._next or self._next.token_type != TokenType.L_PAREN:
4916            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
4917                self._advance()
4918                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
4919
4920            return None
4921
4922        if any_token:
4923            if token_type in self.RESERVED_TOKENS:
4924                return None
4925        elif token_type not in self.FUNC_TOKENS:
4926            return None
4927
4928        self._advance(2)
4929
4930        parser = self.FUNCTION_PARSERS.get(upper)
4931        if parser and not anonymous:
4932            this = parser(self)
4933        else:
4934            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
4935
4936            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
4937                this = self.expression(subquery_predicate, this=self._parse_select())
4938                self._match_r_paren()
4939                return this
4940
4941            if functions is None:
4942                functions = self.FUNCTIONS
4943
4944            function = functions.get(upper)
4945
4946            alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS
4947            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
4948
4949            if alias:
4950                args = self._kv_to_prop_eq(args)
4951
4952            if function and not anonymous:
4953                if "dialect" in function.__code__.co_varnames:
4954                    func = function(args, dialect=self.dialect)
4955                else:
4956                    func = function(args)
4957
4958                func = self.validate_expression(func, args)
4959                if not self.dialect.NORMALIZE_FUNCTIONS:
4960                    func.meta["name"] = this
4961
4962                this = func
4963            else:
4964                if token_type == TokenType.IDENTIFIER:
4965                    this = exp.Identifier(this=this, quoted=True)
4966                this = self.expression(exp.Anonymous, this=this, expressions=args)
4967
4968        if isinstance(this, exp.Expression):
4969            this.add_comments(comments)
4970
4971        self._match_r_paren(this)
4972        return self._parse_window(this)
4973
4974    def _kv_to_prop_eq(self, expressions: t.List[exp.Expression]) -> t.List[exp.Expression]:
4975        transformed = []
4976
4977        for e in expressions:
4978            if isinstance(e, self.KEY_VALUE_DEFINITIONS):
4979                if isinstance(e, exp.Alias):
4980                    e = self.expression(exp.PropertyEQ, this=e.args.get("alias"), expression=e.this)
4981
4982                if not isinstance(e, exp.PropertyEQ):
4983                    e = self.expression(
4984                        exp.PropertyEQ, this=exp.to_identifier(e.this.name), expression=e.expression
4985                    )
4986
4987                if isinstance(e.this, exp.Column):
4988                    e.this.replace(e.this.this)
4989
4990            transformed.append(e)
4991
4992        return transformed
4993
4994    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
4995        return self._parse_column_def(self._parse_id_var())
4996
4997    def _parse_user_defined_function(
4998        self, kind: t.Optional[TokenType] = None
4999    ) -> t.Optional[exp.Expression]:
5000        this = self._parse_id_var()
5001
5002        while self._match(TokenType.DOT):
5003            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
5004
5005        if not self._match(TokenType.L_PAREN):
5006            return this
5007
5008        expressions = self._parse_csv(self._parse_function_parameter)
5009        self._match_r_paren()
5010        return self.expression(
5011            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
5012        )
5013
5014    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
5015        literal = self._parse_primary()
5016        if literal:
5017            return self.expression(exp.Introducer, this=token.text, expression=literal)
5018
5019        return self.expression(exp.Identifier, this=token.text)
5020
5021    def _parse_session_parameter(self) -> exp.SessionParameter:
5022        kind = None
5023        this = self._parse_id_var() or self._parse_primary()
5024
5025        if this and self._match(TokenType.DOT):
5026            kind = this.name
5027            this = self._parse_var() or self._parse_primary()
5028
5029        return self.expression(exp.SessionParameter, this=this, kind=kind)
5030
5031    def _parse_lambda_arg(self) -> t.Optional[exp.Expression]:
5032        return self._parse_id_var()
5033
5034    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
5035        index = self._index
5036
5037        if self._match(TokenType.L_PAREN):
5038            expressions = t.cast(
5039                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_lambda_arg)
5040            )
5041
5042            if not self._match(TokenType.R_PAREN):
5043                self._retreat(index)
5044        else:
5045            expressions = [self._parse_lambda_arg()]
5046
5047        if self._match_set(self.LAMBDAS):
5048            return self.LAMBDAS[self._prev.token_type](self, expressions)
5049
5050        self._retreat(index)
5051
5052        this: t.Optional[exp.Expression]
5053
5054        if self._match(TokenType.DISTINCT):
5055            this = self.expression(
5056                exp.Distinct, expressions=self._parse_csv(self._parse_assignment)
5057            )
5058        else:
5059            this = self._parse_select_or_expression(alias=alias)
5060
5061        return self._parse_limit(
5062            self._parse_order(self._parse_having_max(self._parse_respect_or_ignore_nulls(this)))
5063        )
5064
5065    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
5066        index = self._index
5067        if not self._match(TokenType.L_PAREN):
5068            return this
5069
5070        # Disambiguate between schema and subquery/CTE, e.g. in INSERT INTO table (<expr>),
5071        # expr can be of both types
5072        if self._match_set(self.SELECT_START_TOKENS):
5073            self._retreat(index)
5074            return this
5075        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
5076        self._match_r_paren()
5077        return self.expression(exp.Schema, this=this, expressions=args)
5078
5079    def _parse_field_def(self) -> t.Optional[exp.Expression]:
5080        return self._parse_column_def(self._parse_field(any_token=True))
5081
5082    def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5083        # column defs are not really columns, they're identifiers
5084        if isinstance(this, exp.Column):
5085            this = this.this
5086
5087        kind = self._parse_types(schema=True)
5088
5089        if self._match_text_seq("FOR", "ORDINALITY"):
5090            return self.expression(exp.ColumnDef, this=this, ordinality=True)
5091
5092        constraints: t.List[exp.Expression] = []
5093
5094        if (not kind and self._match(TokenType.ALIAS)) or self._match_texts(
5095            ("ALIAS", "MATERIALIZED")
5096        ):
5097            persisted = self._prev.text.upper() == "MATERIALIZED"
5098            constraints.append(
5099                self.expression(
5100                    exp.ComputedColumnConstraint,
5101                    this=self._parse_assignment(),
5102                    persisted=persisted or self._match_text_seq("PERSISTED"),
5103                    not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
5104                )
5105            )
5106        elif kind and self._match_pair(TokenType.ALIAS, TokenType.L_PAREN, advance=False):
5107            self._match(TokenType.ALIAS)
5108            constraints.append(
5109                self.expression(exp.TransformColumnConstraint, this=self._parse_field())
5110            )
5111
5112        while True:
5113            constraint = self._parse_column_constraint()
5114            if not constraint:
5115                break
5116            constraints.append(constraint)
5117
5118        if not kind and not constraints:
5119            return this
5120
5121        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
5122
5123    def _parse_auto_increment(
5124        self,
5125    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
5126        start = None
5127        increment = None
5128
5129        if self._match(TokenType.L_PAREN, advance=False):
5130            args = self._parse_wrapped_csv(self._parse_bitwise)
5131            start = seq_get(args, 0)
5132            increment = seq_get(args, 1)
5133        elif self._match_text_seq("START"):
5134            start = self._parse_bitwise()
5135            self._match_text_seq("INCREMENT")
5136            increment = self._parse_bitwise()
5137
5138        if start and increment:
5139            return exp.GeneratedAsIdentityColumnConstraint(start=start, increment=increment)
5140
5141        return exp.AutoIncrementColumnConstraint()
5142
5143    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
5144        if not self._match_text_seq("REFRESH"):
5145            self._retreat(self._index - 1)
5146            return None
5147        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
5148
5149    def _parse_compress(self) -> exp.CompressColumnConstraint:
5150        if self._match(TokenType.L_PAREN, advance=False):
5151            return self.expression(
5152                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
5153            )
5154
5155        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
5156
5157    def _parse_generated_as_identity(
5158        self,
5159    ) -> (
5160        exp.GeneratedAsIdentityColumnConstraint
5161        | exp.ComputedColumnConstraint
5162        | exp.GeneratedAsRowColumnConstraint
5163    ):
5164        if self._match_text_seq("BY", "DEFAULT"):
5165            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
5166            this = self.expression(
5167                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
5168            )
5169        else:
5170            self._match_text_seq("ALWAYS")
5171            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
5172
5173        self._match(TokenType.ALIAS)
5174
5175        if self._match_text_seq("ROW"):
5176            start = self._match_text_seq("START")
5177            if not start:
5178                self._match(TokenType.END)
5179            hidden = self._match_text_seq("HIDDEN")
5180            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
5181
5182        identity = self._match_text_seq("IDENTITY")
5183
5184        if self._match(TokenType.L_PAREN):
5185            if self._match(TokenType.START_WITH):
5186                this.set("start", self._parse_bitwise())
5187            if self._match_text_seq("INCREMENT", "BY"):
5188                this.set("increment", self._parse_bitwise())
5189            if self._match_text_seq("MINVALUE"):
5190                this.set("minvalue", self._parse_bitwise())
5191            if self._match_text_seq("MAXVALUE"):
5192                this.set("maxvalue", self._parse_bitwise())
5193
5194            if self._match_text_seq("CYCLE"):
5195                this.set("cycle", True)
5196            elif self._match_text_seq("NO", "CYCLE"):
5197                this.set("cycle", False)
5198
5199            if not identity:
5200                this.set("expression", self._parse_range())
5201            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
5202                args = self._parse_csv(self._parse_bitwise)
5203                this.set("start", seq_get(args, 0))
5204                this.set("increment", seq_get(args, 1))
5205
5206            self._match_r_paren()
5207
5208        return this
5209
5210    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
5211        self._match_text_seq("LENGTH")
5212        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
5213
5214    def _parse_not_constraint(self) -> t.Optional[exp.Expression]:
5215        if self._match_text_seq("NULL"):
5216            return self.expression(exp.NotNullColumnConstraint)
5217        if self._match_text_seq("CASESPECIFIC"):
5218            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
5219        if self._match_text_seq("FOR", "REPLICATION"):
5220            return self.expression(exp.NotForReplicationColumnConstraint)
5221        return None
5222
5223    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
5224        if self._match(TokenType.CONSTRAINT):
5225            this = self._parse_id_var()
5226        else:
5227            this = None
5228
5229        if self._match_texts(self.CONSTRAINT_PARSERS):
5230            return self.expression(
5231                exp.ColumnConstraint,
5232                this=this,
5233                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
5234            )
5235
5236        return this
5237
5238    def _parse_constraint(self) -> t.Optional[exp.Expression]:
5239        if not self._match(TokenType.CONSTRAINT):
5240            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
5241
5242        return self.expression(
5243            exp.Constraint,
5244            this=self._parse_id_var(),
5245            expressions=self._parse_unnamed_constraints(),
5246        )
5247
5248    def _parse_unnamed_constraints(self) -> t.List[exp.Expression]:
5249        constraints = []
5250        while True:
5251            constraint = self._parse_unnamed_constraint() or self._parse_function()
5252            if not constraint:
5253                break
5254            constraints.append(constraint)
5255
5256        return constraints
5257
5258    def _parse_unnamed_constraint(
5259        self, constraints: t.Optional[t.Collection[str]] = None
5260    ) -> t.Optional[exp.Expression]:
5261        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
5262            constraints or self.CONSTRAINT_PARSERS
5263        ):
5264            return None
5265
5266        constraint = self._prev.text.upper()
5267        if constraint not in self.CONSTRAINT_PARSERS:
5268            self.raise_error(f"No parser found for schema constraint {constraint}.")
5269
5270        return self.CONSTRAINT_PARSERS[constraint](self)
5271
5272    def _parse_unique_key(self) -> t.Optional[exp.Expression]:
5273        return self._parse_id_var(any_token=False)
5274
5275    def _parse_unique(self) -> exp.UniqueColumnConstraint:
5276        self._match_text_seq("KEY")
5277        return self.expression(
5278            exp.UniqueColumnConstraint,
5279            nulls=self._match_text_seq("NULLS", "NOT", "DISTINCT"),
5280            this=self._parse_schema(self._parse_unique_key()),
5281            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
5282            on_conflict=self._parse_on_conflict(),
5283        )
5284
5285    def _parse_key_constraint_options(self) -> t.List[str]:
5286        options = []
5287        while True:
5288            if not self._curr:
5289                break
5290
5291            if self._match(TokenType.ON):
5292                action = None
5293                on = self._advance_any() and self._prev.text
5294
5295                if self._match_text_seq("NO", "ACTION"):
5296                    action = "NO ACTION"
5297                elif self._match_text_seq("CASCADE"):
5298                    action = "CASCADE"
5299                elif self._match_text_seq("RESTRICT"):
5300                    action = "RESTRICT"
5301                elif self._match_pair(TokenType.SET, TokenType.NULL):
5302                    action = "SET NULL"
5303                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
5304                    action = "SET DEFAULT"
5305                else:
5306                    self.raise_error("Invalid key constraint")
5307
5308                options.append(f"ON {on} {action}")
5309            else:
5310                var = self._parse_var_from_options(
5311                    self.KEY_CONSTRAINT_OPTIONS, raise_unmatched=False
5312                )
5313                if not var:
5314                    break
5315                options.append(var.name)
5316
5317        return options
5318
5319    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
5320        if match and not self._match(TokenType.REFERENCES):
5321            return None
5322
5323        expressions = None
5324        this = self._parse_table(schema=True)
5325        options = self._parse_key_constraint_options()
5326        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
5327
5328    def _parse_foreign_key(self) -> exp.ForeignKey:
5329        expressions = self._parse_wrapped_id_vars()
5330        reference = self._parse_references()
5331        options = {}
5332
5333        while self._match(TokenType.ON):
5334            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
5335                self.raise_error("Expected DELETE or UPDATE")
5336
5337            kind = self._prev.text.lower()
5338
5339            if self._match_text_seq("NO", "ACTION"):
5340                action = "NO ACTION"
5341            elif self._match(TokenType.SET):
5342                self._match_set((TokenType.NULL, TokenType.DEFAULT))
5343                action = "SET " + self._prev.text.upper()
5344            else:
5345                self._advance()
5346                action = self._prev.text.upper()
5347
5348            options[kind] = action
5349
5350        return self.expression(
5351            exp.ForeignKey,
5352            expressions=expressions,
5353            reference=reference,
5354            **options,  # type: ignore
5355        )
5356
5357    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
5358        return self._parse_field()
5359
5360    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
5361        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
5362            self._retreat(self._index - 1)
5363            return None
5364
5365        id_vars = self._parse_wrapped_id_vars()
5366        return self.expression(
5367            exp.PeriodForSystemTimeConstraint,
5368            this=seq_get(id_vars, 0),
5369            expression=seq_get(id_vars, 1),
5370        )
5371
5372    def _parse_primary_key(
5373        self, wrapped_optional: bool = False, in_props: bool = False
5374    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
5375        desc = (
5376            self._match_set((TokenType.ASC, TokenType.DESC))
5377            and self._prev.token_type == TokenType.DESC
5378        )
5379
5380        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
5381            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
5382
5383        expressions = self._parse_wrapped_csv(
5384            self._parse_primary_key_part, optional=wrapped_optional
5385        )
5386        options = self._parse_key_constraint_options()
5387        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
5388
5389    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
5390        return self._parse_slice(self._parse_alias(self._parse_assignment(), explicit=True))
5391
5392    def _parse_bracket(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
5393        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
5394            return this
5395
5396        bracket_kind = self._prev.token_type
5397        expressions = self._parse_csv(
5398            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
5399        )
5400
5401        if bracket_kind == TokenType.L_BRACKET and not self._match(TokenType.R_BRACKET):
5402            self.raise_error("Expected ]")
5403        elif bracket_kind == TokenType.L_BRACE and not self._match(TokenType.R_BRACE):
5404            self.raise_error("Expected }")
5405
5406        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
5407        if bracket_kind == TokenType.L_BRACE:
5408            this = self.expression(exp.Struct, expressions=self._kv_to_prop_eq(expressions))
5409        elif not this:
5410            this = self.expression(exp.Array, expressions=expressions)
5411        else:
5412            constructor_type = self.ARRAY_CONSTRUCTORS.get(this.name.upper())
5413            if constructor_type:
5414                return self.expression(constructor_type, expressions=expressions)
5415
5416            expressions = apply_index_offset(this, expressions, -self.dialect.INDEX_OFFSET)
5417            this = self.expression(exp.Bracket, this=this, expressions=expressions)
5418
5419        self._add_comments(this)
5420        return self._parse_bracket(this)
5421
5422    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5423        if self._match(TokenType.COLON):
5424            return self.expression(exp.Slice, this=this, expression=self._parse_assignment())
5425        return this
5426
5427    def _parse_case(self) -> t.Optional[exp.Expression]:
5428        ifs = []
5429        default = None
5430
5431        comments = self._prev_comments
5432        expression = self._parse_assignment()
5433
5434        while self._match(TokenType.WHEN):
5435            this = self._parse_assignment()
5436            self._match(TokenType.THEN)
5437            then = self._parse_assignment()
5438            ifs.append(self.expression(exp.If, this=this, true=then))
5439
5440        if self._match(TokenType.ELSE):
5441            default = self._parse_assignment()
5442
5443        if not self._match(TokenType.END):
5444            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
5445                default = exp.column("interval")
5446            else:
5447                self.raise_error("Expected END after CASE", self._prev)
5448
5449        return self.expression(
5450            exp.Case, comments=comments, this=expression, ifs=ifs, default=default
5451        )
5452
5453    def _parse_if(self) -> t.Optional[exp.Expression]:
5454        if self._match(TokenType.L_PAREN):
5455            args = self._parse_csv(self._parse_assignment)
5456            this = self.validate_expression(exp.If.from_arg_list(args), args)
5457            self._match_r_paren()
5458        else:
5459            index = self._index - 1
5460
5461            if self.NO_PAREN_IF_COMMANDS and index == 0:
5462                return self._parse_as_command(self._prev)
5463
5464            condition = self._parse_assignment()
5465
5466            if not condition:
5467                self._retreat(index)
5468                return None
5469
5470            self._match(TokenType.THEN)
5471            true = self._parse_assignment()
5472            false = self._parse_assignment() if self._match(TokenType.ELSE) else None
5473            self._match(TokenType.END)
5474            this = self.expression(exp.If, this=condition, true=true, false=false)
5475
5476        return this
5477
5478    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
5479        if not self._match_text_seq("VALUE", "FOR"):
5480            self._retreat(self._index - 1)
5481            return None
5482
5483        return self.expression(
5484            exp.NextValueFor,
5485            this=self._parse_column(),
5486            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
5487        )
5488
5489    def _parse_extract(self) -> exp.Extract | exp.Anonymous:
5490        this = self._parse_function() or self._parse_var_or_string(upper=True)
5491
5492        if self._match(TokenType.FROM):
5493            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
5494
5495        if not self._match(TokenType.COMMA):
5496            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
5497
5498        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
5499
5500    def _parse_gap_fill(self) -> exp.GapFill:
5501        self._match(TokenType.TABLE)
5502        this = self._parse_table()
5503
5504        self._match(TokenType.COMMA)
5505        args = [this, *self._parse_csv(self._parse_lambda)]
5506
5507        gap_fill = exp.GapFill.from_arg_list(args)
5508        return self.validate_expression(gap_fill, args)
5509
5510    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
5511        this = self._parse_assignment()
5512
5513        if not self._match(TokenType.ALIAS):
5514            if self._match(TokenType.COMMA):
5515                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
5516
5517            self.raise_error("Expected AS after CAST")
5518
5519        fmt = None
5520        to = self._parse_types()
5521
5522        if self._match(TokenType.FORMAT):
5523            fmt_string = self._parse_string()
5524            fmt = self._parse_at_time_zone(fmt_string)
5525
5526            if not to:
5527                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
5528            if to.this in exp.DataType.TEMPORAL_TYPES:
5529                this = self.expression(
5530                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
5531                    this=this,
5532                    format=exp.Literal.string(
5533                        format_time(
5534                            fmt_string.this if fmt_string else "",
5535                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
5536                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
5537                        )
5538                    ),
5539                    safe=safe,
5540                )
5541
5542                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
5543                    this.set("zone", fmt.args["zone"])
5544                return this
5545        elif not to:
5546            self.raise_error("Expected TYPE after CAST")
5547        elif isinstance(to, exp.Identifier):
5548            to = exp.DataType.build(to.name, udt=True)
5549        elif to.this == exp.DataType.Type.CHAR:
5550            if self._match(TokenType.CHARACTER_SET):
5551                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
5552
5553        return self.expression(
5554            exp.Cast if strict else exp.TryCast,
5555            this=this,
5556            to=to,
5557            format=fmt,
5558            safe=safe,
5559            action=self._parse_var_from_options(self.CAST_ACTIONS, raise_unmatched=False),
5560        )
5561
5562    def _parse_string_agg(self) -> exp.Expression:
5563        if self._match(TokenType.DISTINCT):
5564            args: t.List[t.Optional[exp.Expression]] = [
5565                self.expression(exp.Distinct, expressions=[self._parse_assignment()])
5566            ]
5567            if self._match(TokenType.COMMA):
5568                args.extend(self._parse_csv(self._parse_assignment))
5569        else:
5570            args = self._parse_csv(self._parse_assignment)  # type: ignore
5571
5572        index = self._index
5573        if not self._match(TokenType.R_PAREN) and args:
5574            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
5575            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
5576            args[-1] = self._parse_limit(this=self._parse_order(this=args[-1]))
5577            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
5578
5579        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
5580        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
5581        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
5582        if not self._match_text_seq("WITHIN", "GROUP"):
5583            self._retreat(index)
5584            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
5585
5586        self._match_l_paren()  # The corresponding match_r_paren will be called in parse_function (caller)
5587        order = self._parse_order(this=seq_get(args, 0))
5588        return self.expression(exp.GroupConcat, this=order, separator=seq_get(args, 1))
5589
5590    def _parse_convert(
5591        self, strict: bool, safe: t.Optional[bool] = None
5592    ) -> t.Optional[exp.Expression]:
5593        this = self._parse_bitwise()
5594
5595        if self._match(TokenType.USING):
5596            to: t.Optional[exp.Expression] = self.expression(
5597                exp.CharacterSet, this=self._parse_var()
5598            )
5599        elif self._match(TokenType.COMMA):
5600            to = self._parse_types()
5601        else:
5602            to = None
5603
5604        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
5605
5606    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
5607        """
5608        There are generally two variants of the DECODE function:
5609
5610        - DECODE(bin, charset)
5611        - DECODE(expression, search, result [, search, result] ... [, default])
5612
5613        The second variant will always be parsed into a CASE expression. Note that NULL
5614        needs special treatment, since we need to explicitly check for it with `IS NULL`,
5615        instead of relying on pattern matching.
5616        """
5617        args = self._parse_csv(self._parse_assignment)
5618
5619        if len(args) < 3:
5620            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
5621
5622        expression, *expressions = args
5623        if not expression:
5624            return None
5625
5626        ifs = []
5627        for search, result in zip(expressions[::2], expressions[1::2]):
5628            if not search or not result:
5629                return None
5630
5631            if isinstance(search, exp.Literal):
5632                ifs.append(
5633                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
5634                )
5635            elif isinstance(search, exp.Null):
5636                ifs.append(
5637                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
5638                )
5639            else:
5640                cond = exp.or_(
5641                    exp.EQ(this=expression.copy(), expression=search),
5642                    exp.and_(
5643                        exp.Is(this=expression.copy(), expression=exp.Null()),
5644                        exp.Is(this=search.copy(), expression=exp.Null()),
5645                        copy=False,
5646                    ),
5647                    copy=False,
5648                )
5649                ifs.append(exp.If(this=cond, true=result))
5650
5651        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
5652
5653    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
5654        self._match_text_seq("KEY")
5655        key = self._parse_column()
5656        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
5657        self._match_text_seq("VALUE")
5658        value = self._parse_bitwise()
5659
5660        if not key and not value:
5661            return None
5662        return self.expression(exp.JSONKeyValue, this=key, expression=value)
5663
5664    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5665        if not this or not self._match_text_seq("FORMAT", "JSON"):
5666            return this
5667
5668        return self.expression(exp.FormatJson, this=this)
5669
5670    def _parse_on_handling(self, on: str, *values: str) -> t.Optional[str]:
5671        # Parses the "X ON Y" syntax, i.e. NULL ON NULL (Oracle, T-SQL)
5672        for value in values:
5673            if self._match_text_seq(value, "ON", on):
5674                return f"{value} ON {on}"
5675
5676        return None
5677
5678    @t.overload
5679    def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
5680
5681    @t.overload
5682    def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
5683
5684    def _parse_json_object(self, agg=False):
5685        star = self._parse_star()
5686        expressions = (
5687            [star]
5688            if star
5689            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
5690        )
5691        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
5692
5693        unique_keys = None
5694        if self._match_text_seq("WITH", "UNIQUE"):
5695            unique_keys = True
5696        elif self._match_text_seq("WITHOUT", "UNIQUE"):
5697            unique_keys = False
5698
5699        self._match_text_seq("KEYS")
5700
5701        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
5702            self._parse_type()
5703        )
5704        encoding = self._match_text_seq("ENCODING") and self._parse_var()
5705
5706        return self.expression(
5707            exp.JSONObjectAgg if agg else exp.JSONObject,
5708            expressions=expressions,
5709            null_handling=null_handling,
5710            unique_keys=unique_keys,
5711            return_type=return_type,
5712            encoding=encoding,
5713        )
5714
5715    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
5716    def _parse_json_column_def(self) -> exp.JSONColumnDef:
5717        if not self._match_text_seq("NESTED"):
5718            this = self._parse_id_var()
5719            kind = self._parse_types(allow_identifiers=False)
5720            nested = None
5721        else:
5722            this = None
5723            kind = None
5724            nested = True
5725
5726        path = self._match_text_seq("PATH") and self._parse_string()
5727        nested_schema = nested and self._parse_json_schema()
5728
5729        return self.expression(
5730            exp.JSONColumnDef,
5731            this=this,
5732            kind=kind,
5733            path=path,
5734            nested_schema=nested_schema,
5735        )
5736
5737    def _parse_json_schema(self) -> exp.JSONSchema:
5738        self._match_text_seq("COLUMNS")
5739        return self.expression(
5740            exp.JSONSchema,
5741            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
5742        )
5743
5744    def _parse_json_table(self) -> exp.JSONTable:
5745        this = self._parse_format_json(self._parse_bitwise())
5746        path = self._match(TokenType.COMMA) and self._parse_string()
5747        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
5748        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
5749        schema = self._parse_json_schema()
5750
5751        return exp.JSONTable(
5752            this=this,
5753            schema=schema,
5754            path=path,
5755            error_handling=error_handling,
5756            empty_handling=empty_handling,
5757        )
5758
5759    def _parse_match_against(self) -> exp.MatchAgainst:
5760        expressions = self._parse_csv(self._parse_column)
5761
5762        self._match_text_seq(")", "AGAINST", "(")
5763
5764        this = self._parse_string()
5765
5766        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
5767            modifier = "IN NATURAL LANGUAGE MODE"
5768            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
5769                modifier = f"{modifier} WITH QUERY EXPANSION"
5770        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
5771            modifier = "IN BOOLEAN MODE"
5772        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
5773            modifier = "WITH QUERY EXPANSION"
5774        else:
5775            modifier = None
5776
5777        return self.expression(
5778            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
5779        )
5780
5781    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
5782    def _parse_open_json(self) -> exp.OpenJSON:
5783        this = self._parse_bitwise()
5784        path = self._match(TokenType.COMMA) and self._parse_string()
5785
5786        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
5787            this = self._parse_field(any_token=True)
5788            kind = self._parse_types()
5789            path = self._parse_string()
5790            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
5791
5792            return self.expression(
5793                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
5794            )
5795
5796        expressions = None
5797        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
5798            self._match_l_paren()
5799            expressions = self._parse_csv(_parse_open_json_column_def)
5800
5801        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
5802
5803    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
5804        args = self._parse_csv(self._parse_bitwise)
5805
5806        if self._match(TokenType.IN):
5807            return self.expression(
5808                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
5809            )
5810
5811        if haystack_first:
5812            haystack = seq_get(args, 0)
5813            needle = seq_get(args, 1)
5814        else:
5815            needle = seq_get(args, 0)
5816            haystack = seq_get(args, 1)
5817
5818        return self.expression(
5819            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
5820        )
5821
5822    def _parse_predict(self) -> exp.Predict:
5823        self._match_text_seq("MODEL")
5824        this = self._parse_table()
5825
5826        self._match(TokenType.COMMA)
5827        self._match_text_seq("TABLE")
5828
5829        return self.expression(
5830            exp.Predict,
5831            this=this,
5832            expression=self._parse_table(),
5833            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
5834        )
5835
5836    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
5837        args = self._parse_csv(self._parse_table)
5838        return exp.JoinHint(this=func_name.upper(), expressions=args)
5839
5840    def _parse_substring(self) -> exp.Substring:
5841        # Postgres supports the form: substring(string [from int] [for int])
5842        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
5843
5844        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
5845
5846        if self._match(TokenType.FROM):
5847            args.append(self._parse_bitwise())
5848        if self._match(TokenType.FOR):
5849            if len(args) == 1:
5850                args.append(exp.Literal.number(1))
5851            args.append(self._parse_bitwise())
5852
5853        return self.validate_expression(exp.Substring.from_arg_list(args), args)
5854
5855    def _parse_trim(self) -> exp.Trim:
5856        # https://www.w3resource.com/sql/character-functions/trim.php
5857        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
5858
5859        position = None
5860        collation = None
5861        expression = None
5862
5863        if self._match_texts(self.TRIM_TYPES):
5864            position = self._prev.text.upper()
5865
5866        this = self._parse_bitwise()
5867        if self._match_set((TokenType.FROM, TokenType.COMMA)):
5868            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
5869            expression = self._parse_bitwise()
5870
5871            if invert_order:
5872                this, expression = expression, this
5873
5874        if self._match(TokenType.COLLATE):
5875            collation = self._parse_bitwise()
5876
5877        return self.expression(
5878            exp.Trim, this=this, position=position, expression=expression, collation=collation
5879        )
5880
5881    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
5882        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
5883
5884    def _parse_named_window(self) -> t.Optional[exp.Expression]:
5885        return self._parse_window(self._parse_id_var(), alias=True)
5886
5887    def _parse_respect_or_ignore_nulls(
5888        self, this: t.Optional[exp.Expression]
5889    ) -> t.Optional[exp.Expression]:
5890        if self._match_text_seq("IGNORE", "NULLS"):
5891            return self.expression(exp.IgnoreNulls, this=this)
5892        if self._match_text_seq("RESPECT", "NULLS"):
5893            return self.expression(exp.RespectNulls, this=this)
5894        return this
5895
5896    def _parse_having_max(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5897        if self._match(TokenType.HAVING):
5898            self._match_texts(("MAX", "MIN"))
5899            max = self._prev.text.upper() != "MIN"
5900            return self.expression(
5901                exp.HavingMax, this=this, expression=self._parse_column(), max=max
5902            )
5903
5904        return this
5905
5906    def _parse_window(
5907        self, this: t.Optional[exp.Expression], alias: bool = False
5908    ) -> t.Optional[exp.Expression]:
5909        func = this
5910        comments = func.comments if isinstance(func, exp.Expression) else None
5911
5912        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
5913            self._match(TokenType.WHERE)
5914            this = self.expression(
5915                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
5916            )
5917            self._match_r_paren()
5918
5919        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
5920        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
5921        if self._match_text_seq("WITHIN", "GROUP"):
5922            order = self._parse_wrapped(self._parse_order)
5923            this = self.expression(exp.WithinGroup, this=this, expression=order)
5924
5925        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
5926        # Some dialects choose to implement and some do not.
5927        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
5928
5929        # There is some code above in _parse_lambda that handles
5930        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
5931
5932        # The below changes handle
5933        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
5934
5935        # Oracle allows both formats
5936        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
5937        #   and Snowflake chose to do the same for familiarity
5938        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
5939        if isinstance(this, exp.AggFunc):
5940            ignore_respect = this.find(exp.IgnoreNulls, exp.RespectNulls)
5941
5942            if ignore_respect and ignore_respect is not this:
5943                ignore_respect.replace(ignore_respect.this)
5944                this = self.expression(ignore_respect.__class__, this=this)
5945
5946        this = self._parse_respect_or_ignore_nulls(this)
5947
5948        # bigquery select from window x AS (partition by ...)
5949        if alias:
5950            over = None
5951            self._match(TokenType.ALIAS)
5952        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
5953            return this
5954        else:
5955            over = self._prev.text.upper()
5956
5957        if comments and isinstance(func, exp.Expression):
5958            func.pop_comments()
5959
5960        if not self._match(TokenType.L_PAREN):
5961            return self.expression(
5962                exp.Window,
5963                comments=comments,
5964                this=this,
5965                alias=self._parse_id_var(False),
5966                over=over,
5967            )
5968
5969        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
5970
5971        first = self._match(TokenType.FIRST)
5972        if self._match_text_seq("LAST"):
5973            first = False
5974
5975        partition, order = self._parse_partition_and_order()
5976        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
5977
5978        if kind:
5979            self._match(TokenType.BETWEEN)
5980            start = self._parse_window_spec()
5981            self._match(TokenType.AND)
5982            end = self._parse_window_spec()
5983
5984            spec = self.expression(
5985                exp.WindowSpec,
5986                kind=kind,
5987                start=start["value"],
5988                start_side=start["side"],
5989                end=end["value"],
5990                end_side=end["side"],
5991            )
5992        else:
5993            spec = None
5994
5995        self._match_r_paren()
5996
5997        window = self.expression(
5998            exp.Window,
5999            comments=comments,
6000            this=this,
6001            partition_by=partition,
6002            order=order,
6003            spec=spec,
6004            alias=window_alias,
6005            over=over,
6006            first=first,
6007        )
6008
6009        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
6010        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
6011            return self._parse_window(window, alias=alias)
6012
6013        return window
6014
6015    def _parse_partition_and_order(
6016        self,
6017    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
6018        return self._parse_partition_by(), self._parse_order()
6019
6020    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
6021        self._match(TokenType.BETWEEN)
6022
6023        return {
6024            "value": (
6025                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
6026                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
6027                or self._parse_bitwise()
6028            ),
6029            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
6030        }
6031
6032    def _parse_alias(
6033        self, this: t.Optional[exp.Expression], explicit: bool = False
6034    ) -> t.Optional[exp.Expression]:
6035        any_token = self._match(TokenType.ALIAS)
6036        comments = self._prev_comments or []
6037
6038        if explicit and not any_token:
6039            return this
6040
6041        if self._match(TokenType.L_PAREN):
6042            aliases = self.expression(
6043                exp.Aliases,
6044                comments=comments,
6045                this=this,
6046                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
6047            )
6048            self._match_r_paren(aliases)
6049            return aliases
6050
6051        alias = self._parse_id_var(any_token, tokens=self.ALIAS_TOKENS) or (
6052            self.STRING_ALIASES and self._parse_string_as_identifier()
6053        )
6054
6055        if alias:
6056            comments.extend(alias.pop_comments())
6057            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
6058            column = this.this
6059
6060            # Moves the comment next to the alias in `expr /* comment */ AS alias`
6061            if not this.comments and column and column.comments:
6062                this.comments = column.pop_comments()
6063
6064        return this
6065
6066    def _parse_id_var(
6067        self,
6068        any_token: bool = True,
6069        tokens: t.Optional[t.Collection[TokenType]] = None,
6070    ) -> t.Optional[exp.Expression]:
6071        expression = self._parse_identifier()
6072        if not expression and (
6073            (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS)
6074        ):
6075            quoted = self._prev.token_type == TokenType.STRING
6076            expression = self.expression(exp.Identifier, this=self._prev.text, quoted=quoted)
6077
6078        return expression
6079
6080    def _parse_string(self) -> t.Optional[exp.Expression]:
6081        if self._match_set(self.STRING_PARSERS):
6082            return self.STRING_PARSERS[self._prev.token_type](self, self._prev)
6083        return self._parse_placeholder()
6084
6085    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
6086        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
6087
6088    def _parse_number(self) -> t.Optional[exp.Expression]:
6089        if self._match_set(self.NUMERIC_PARSERS):
6090            return self.NUMERIC_PARSERS[self._prev.token_type](self, self._prev)
6091        return self._parse_placeholder()
6092
6093    def _parse_identifier(self) -> t.Optional[exp.Expression]:
6094        if self._match(TokenType.IDENTIFIER):
6095            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
6096        return self._parse_placeholder()
6097
6098    def _parse_var(
6099        self,
6100        any_token: bool = False,
6101        tokens: t.Optional[t.Collection[TokenType]] = None,
6102        upper: bool = False,
6103    ) -> t.Optional[exp.Expression]:
6104        if (
6105            (any_token and self._advance_any())
6106            or self._match(TokenType.VAR)
6107            or (self._match_set(tokens) if tokens else False)
6108        ):
6109            return self.expression(
6110                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
6111            )
6112        return self._parse_placeholder()
6113
6114    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
6115        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
6116            self._advance()
6117            return self._prev
6118        return None
6119
6120    def _parse_var_or_string(self, upper: bool = False) -> t.Optional[exp.Expression]:
6121        return self._parse_string() or self._parse_var(any_token=True, upper=upper)
6122
6123    def _parse_primary_or_var(self) -> t.Optional[exp.Expression]:
6124        return self._parse_primary() or self._parse_var(any_token=True)
6125
6126    def _parse_null(self) -> t.Optional[exp.Expression]:
6127        if self._match_set(self.NULL_TOKENS):
6128            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
6129        return self._parse_placeholder()
6130
6131    def _parse_boolean(self) -> t.Optional[exp.Expression]:
6132        if self._match(TokenType.TRUE):
6133            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
6134        if self._match(TokenType.FALSE):
6135            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
6136        return self._parse_placeholder()
6137
6138    def _parse_star(self) -> t.Optional[exp.Expression]:
6139        if self._match(TokenType.STAR):
6140            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
6141        return self._parse_placeholder()
6142
6143    def _parse_parameter(self) -> exp.Parameter:
6144        this = self._parse_identifier() or self._parse_primary_or_var()
6145        return self.expression(exp.Parameter, this=this)
6146
6147    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
6148        if self._match_set(self.PLACEHOLDER_PARSERS):
6149            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
6150            if placeholder:
6151                return placeholder
6152            self._advance(-1)
6153        return None
6154
6155    def _parse_star_op(self, *keywords: str) -> t.Optional[t.List[exp.Expression]]:
6156        if not self._match_texts(keywords):
6157            return None
6158        if self._match(TokenType.L_PAREN, advance=False):
6159            return self._parse_wrapped_csv(self._parse_expression)
6160
6161        expression = self._parse_expression()
6162        return [expression] if expression else None
6163
6164    def _parse_csv(
6165        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
6166    ) -> t.List[exp.Expression]:
6167        parse_result = parse_method()
6168        items = [parse_result] if parse_result is not None else []
6169
6170        while self._match(sep):
6171            self._add_comments(parse_result)
6172            parse_result = parse_method()
6173            if parse_result is not None:
6174                items.append(parse_result)
6175
6176        return items
6177
6178    def _parse_tokens(
6179        self, parse_method: t.Callable, expressions: t.Dict
6180    ) -> t.Optional[exp.Expression]:
6181        this = parse_method()
6182
6183        while self._match_set(expressions):
6184            this = self.expression(
6185                expressions[self._prev.token_type],
6186                this=this,
6187                comments=self._prev_comments,
6188                expression=parse_method(),
6189            )
6190
6191        return this
6192
6193    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
6194        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
6195
6196    def _parse_wrapped_csv(
6197        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
6198    ) -> t.List[exp.Expression]:
6199        return self._parse_wrapped(
6200            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
6201        )
6202
6203    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
6204        wrapped = self._match(TokenType.L_PAREN)
6205        if not wrapped and not optional:
6206            self.raise_error("Expecting (")
6207        parse_result = parse_method()
6208        if wrapped:
6209            self._match_r_paren()
6210        return parse_result
6211
6212    def _parse_expressions(self) -> t.List[exp.Expression]:
6213        return self._parse_csv(self._parse_expression)
6214
6215    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
6216        return self._parse_select() or self._parse_set_operations(
6217            self._parse_expression() if alias else self._parse_assignment()
6218        )
6219
6220    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
6221        return self._parse_query_modifiers(
6222            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
6223        )
6224
6225    def _parse_transaction(self) -> exp.Transaction | exp.Command:
6226        this = None
6227        if self._match_texts(self.TRANSACTION_KIND):
6228            this = self._prev.text
6229
6230        self._match_texts(("TRANSACTION", "WORK"))
6231
6232        modes = []
6233        while True:
6234            mode = []
6235            while self._match(TokenType.VAR):
6236                mode.append(self._prev.text)
6237
6238            if mode:
6239                modes.append(" ".join(mode))
6240            if not self._match(TokenType.COMMA):
6241                break
6242
6243        return self.expression(exp.Transaction, this=this, modes=modes)
6244
6245    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
6246        chain = None
6247        savepoint = None
6248        is_rollback = self._prev.token_type == TokenType.ROLLBACK
6249
6250        self._match_texts(("TRANSACTION", "WORK"))
6251
6252        if self._match_text_seq("TO"):
6253            self._match_text_seq("SAVEPOINT")
6254            savepoint = self._parse_id_var()
6255
6256        if self._match(TokenType.AND):
6257            chain = not self._match_text_seq("NO")
6258            self._match_text_seq("CHAIN")
6259
6260        if is_rollback:
6261            return self.expression(exp.Rollback, savepoint=savepoint)
6262
6263        return self.expression(exp.Commit, chain=chain)
6264
6265    def _parse_refresh(self) -> exp.Refresh:
6266        self._match(TokenType.TABLE)
6267        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
6268
6269    def _parse_add_column(self) -> t.Optional[exp.Expression]:
6270        if not self._match_text_seq("ADD"):
6271            return None
6272
6273        self._match(TokenType.COLUMN)
6274        exists_column = self._parse_exists(not_=True)
6275        expression = self._parse_field_def()
6276
6277        if expression:
6278            expression.set("exists", exists_column)
6279
6280            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
6281            if self._match_texts(("FIRST", "AFTER")):
6282                position = self._prev.text
6283                column_position = self.expression(
6284                    exp.ColumnPosition, this=self._parse_column(), position=position
6285                )
6286                expression.set("position", column_position)
6287
6288        return expression
6289
6290    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
6291        drop = self._match(TokenType.DROP) and self._parse_drop()
6292        if drop and not isinstance(drop, exp.Command):
6293            drop.set("kind", drop.args.get("kind", "COLUMN"))
6294        return drop
6295
6296    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
6297    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
6298        return self.expression(
6299            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
6300        )
6301
6302    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
6303        index = self._index - 1
6304
6305        if self._match_set(self.ADD_CONSTRAINT_TOKENS, advance=False):
6306            return self._parse_csv(
6307                lambda: self.expression(
6308                    exp.AddConstraint, expressions=self._parse_csv(self._parse_constraint)
6309                )
6310            )
6311
6312        self._retreat(index)
6313        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
6314            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
6315
6316        if self._match_text_seq("ADD", "COLUMNS"):
6317            schema = self._parse_schema()
6318            if schema:
6319                return [schema]
6320            return []
6321
6322        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
6323
6324    def _parse_alter_table_alter(self) -> t.Optional[exp.Expression]:
6325        if self._match_texts(self.ALTER_ALTER_PARSERS):
6326            return self.ALTER_ALTER_PARSERS[self._prev.text.upper()](self)
6327
6328        # Many dialects support the ALTER [COLUMN] syntax, so if there is no
6329        # keyword after ALTER we default to parsing this statement
6330        self._match(TokenType.COLUMN)
6331        column = self._parse_field(any_token=True)
6332
6333        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
6334            return self.expression(exp.AlterColumn, this=column, drop=True)
6335        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
6336            return self.expression(exp.AlterColumn, this=column, default=self._parse_assignment())
6337        if self._match(TokenType.COMMENT):
6338            return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
6339        if self._match_text_seq("DROP", "NOT", "NULL"):
6340            return self.expression(
6341                exp.AlterColumn,
6342                this=column,
6343                drop=True,
6344                allow_null=True,
6345            )
6346        if self._match_text_seq("SET", "NOT", "NULL"):
6347            return self.expression(
6348                exp.AlterColumn,
6349                this=column,
6350                allow_null=False,
6351            )
6352        self._match_text_seq("SET", "DATA")
6353        self._match_text_seq("TYPE")
6354        return self.expression(
6355            exp.AlterColumn,
6356            this=column,
6357            dtype=self._parse_types(),
6358            collate=self._match(TokenType.COLLATE) and self._parse_term(),
6359            using=self._match(TokenType.USING) and self._parse_assignment(),
6360        )
6361
6362    def _parse_alter_diststyle(self) -> exp.AlterDistStyle:
6363        if self._match_texts(("ALL", "EVEN", "AUTO")):
6364            return self.expression(exp.AlterDistStyle, this=exp.var(self._prev.text.upper()))
6365
6366        self._match_text_seq("KEY", "DISTKEY")
6367        return self.expression(exp.AlterDistStyle, this=self._parse_column())
6368
6369    def _parse_alter_sortkey(self, compound: t.Optional[bool] = None) -> exp.AlterSortKey:
6370        if compound:
6371            self._match_text_seq("SORTKEY")
6372
6373        if self._match(TokenType.L_PAREN, advance=False):
6374            return self.expression(
6375                exp.AlterSortKey, expressions=self._parse_wrapped_id_vars(), compound=compound
6376            )
6377
6378        self._match_texts(("AUTO", "NONE"))
6379        return self.expression(
6380            exp.AlterSortKey, this=exp.var(self._prev.text.upper()), compound=compound
6381        )
6382
6383    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
6384        index = self._index - 1
6385
6386        partition_exists = self._parse_exists()
6387        if self._match(TokenType.PARTITION, advance=False):
6388            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
6389
6390        self._retreat(index)
6391        return self._parse_csv(self._parse_drop_column)
6392
6393    def _parse_alter_table_rename(self) -> t.Optional[exp.RenameTable | exp.RenameColumn]:
6394        if self._match(TokenType.COLUMN):
6395            exists = self._parse_exists()
6396            old_column = self._parse_column()
6397            to = self._match_text_seq("TO")
6398            new_column = self._parse_column()
6399
6400            if old_column is None or to is None or new_column is None:
6401                return None
6402
6403            return self.expression(exp.RenameColumn, this=old_column, to=new_column, exists=exists)
6404
6405        self._match_text_seq("TO")
6406        return self.expression(exp.RenameTable, this=self._parse_table(schema=True))
6407
6408    def _parse_alter_table_set(self) -> exp.AlterSet:
6409        alter_set = self.expression(exp.AlterSet)
6410
6411        if self._match(TokenType.L_PAREN, advance=False) or self._match_text_seq(
6412            "TABLE", "PROPERTIES"
6413        ):
6414            alter_set.set("expressions", self._parse_wrapped_csv(self._parse_assignment))
6415        elif self._match_text_seq("FILESTREAM_ON", advance=False):
6416            alter_set.set("expressions", [self._parse_assignment()])
6417        elif self._match_texts(("LOGGED", "UNLOGGED")):
6418            alter_set.set("option", exp.var(self._prev.text.upper()))
6419        elif self._match_text_seq("WITHOUT") and self._match_texts(("CLUSTER", "OIDS")):
6420            alter_set.set("option", exp.var(f"WITHOUT {self._prev.text.upper()}"))
6421        elif self._match_text_seq("LOCATION"):
6422            alter_set.set("location", self._parse_field())
6423        elif self._match_text_seq("ACCESS", "METHOD"):
6424            alter_set.set("access_method", self._parse_field())
6425        elif self._match_text_seq("TABLESPACE"):
6426            alter_set.set("tablespace", self._parse_field())
6427        elif self._match_text_seq("FILE", "FORMAT") or self._match_text_seq("FILEFORMAT"):
6428            alter_set.set("file_format", [self._parse_field()])
6429        elif self._match_text_seq("STAGE_FILE_FORMAT"):
6430            alter_set.set("file_format", self._parse_wrapped_options())
6431        elif self._match_text_seq("STAGE_COPY_OPTIONS"):
6432            alter_set.set("copy_options", self._parse_wrapped_options())
6433        elif self._match_text_seq("TAG") or self._match_text_seq("TAGS"):
6434            alter_set.set("tag", self._parse_csv(self._parse_assignment))
6435        else:
6436            if self._match_text_seq("SERDE"):
6437                alter_set.set("serde", self._parse_field())
6438
6439            alter_set.set("expressions", [self._parse_properties()])
6440
6441        return alter_set
6442
6443    def _parse_alter(self) -> exp.AlterTable | exp.Command:
6444        start = self._prev
6445
6446        if not self._match(TokenType.TABLE):
6447            return self._parse_as_command(start)
6448
6449        exists = self._parse_exists()
6450        only = self._match_text_seq("ONLY")
6451        this = self._parse_table(schema=True)
6452        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
6453
6454        if self._next:
6455            self._advance()
6456
6457        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
6458        if parser:
6459            actions = ensure_list(parser(self))
6460            options = self._parse_csv(self._parse_property)
6461
6462            if not self._curr and actions:
6463                return self.expression(
6464                    exp.AlterTable,
6465                    this=this,
6466                    exists=exists,
6467                    actions=actions,
6468                    only=only,
6469                    options=options,
6470                    cluster=cluster,
6471                )
6472
6473        return self._parse_as_command(start)
6474
6475    def _parse_merge(self) -> exp.Merge:
6476        self._match(TokenType.INTO)
6477        target = self._parse_table()
6478
6479        if target and self._match(TokenType.ALIAS, advance=False):
6480            target.set("alias", self._parse_table_alias())
6481
6482        self._match(TokenType.USING)
6483        using = self._parse_table()
6484
6485        self._match(TokenType.ON)
6486        on = self._parse_assignment()
6487
6488        return self.expression(
6489            exp.Merge,
6490            this=target,
6491            using=using,
6492            on=on,
6493            expressions=self._parse_when_matched(),
6494        )
6495
6496    def _parse_when_matched(self) -> t.List[exp.When]:
6497        whens = []
6498
6499        while self._match(TokenType.WHEN):
6500            matched = not self._match(TokenType.NOT)
6501            self._match_text_seq("MATCHED")
6502            source = (
6503                False
6504                if self._match_text_seq("BY", "TARGET")
6505                else self._match_text_seq("BY", "SOURCE")
6506            )
6507            condition = self._parse_assignment() if self._match(TokenType.AND) else None
6508
6509            self._match(TokenType.THEN)
6510
6511            if self._match(TokenType.INSERT):
6512                _this = self._parse_star()
6513                if _this:
6514                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=_this)
6515                else:
6516                    then = self.expression(
6517                        exp.Insert,
6518                        this=self._parse_value(),
6519                        expression=self._match_text_seq("VALUES") and self._parse_value(),
6520                    )
6521            elif self._match(TokenType.UPDATE):
6522                expressions = self._parse_star()
6523                if expressions:
6524                    then = self.expression(exp.Update, expressions=expressions)
6525                else:
6526                    then = self.expression(
6527                        exp.Update,
6528                        expressions=self._match(TokenType.SET)
6529                        and self._parse_csv(self._parse_equality),
6530                    )
6531            elif self._match(TokenType.DELETE):
6532                then = self.expression(exp.Var, this=self._prev.text)
6533            else:
6534                then = None
6535
6536            whens.append(
6537                self.expression(
6538                    exp.When,
6539                    matched=matched,
6540                    source=source,
6541                    condition=condition,
6542                    then=then,
6543                )
6544            )
6545        return whens
6546
6547    def _parse_show(self) -> t.Optional[exp.Expression]:
6548        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
6549        if parser:
6550            return parser(self)
6551        return self._parse_as_command(self._prev)
6552
6553    def _parse_set_item_assignment(
6554        self, kind: t.Optional[str] = None
6555    ) -> t.Optional[exp.Expression]:
6556        index = self._index
6557
6558        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
6559            return self._parse_set_transaction(global_=kind == "GLOBAL")
6560
6561        left = self._parse_primary() or self._parse_column()
6562        assignment_delimiter = self._match_texts(("=", "TO"))
6563
6564        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
6565            self._retreat(index)
6566            return None
6567
6568        right = self._parse_statement() or self._parse_id_var()
6569        if isinstance(right, (exp.Column, exp.Identifier)):
6570            right = exp.var(right.name)
6571
6572        this = self.expression(exp.EQ, this=left, expression=right)
6573        return self.expression(exp.SetItem, this=this, kind=kind)
6574
6575    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
6576        self._match_text_seq("TRANSACTION")
6577        characteristics = self._parse_csv(
6578            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
6579        )
6580        return self.expression(
6581            exp.SetItem,
6582            expressions=characteristics,
6583            kind="TRANSACTION",
6584            **{"global": global_},  # type: ignore
6585        )
6586
6587    def _parse_set_item(self) -> t.Optional[exp.Expression]:
6588        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
6589        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
6590
6591    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
6592        index = self._index
6593        set_ = self.expression(
6594            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
6595        )
6596
6597        if self._curr:
6598            self._retreat(index)
6599            return self._parse_as_command(self._prev)
6600
6601        return set_
6602
6603    def _parse_var_from_options(
6604        self, options: OPTIONS_TYPE, raise_unmatched: bool = True
6605    ) -> t.Optional[exp.Var]:
6606        start = self._curr
6607        if not start:
6608            return None
6609
6610        option = start.text.upper()
6611        continuations = options.get(option)
6612
6613        index = self._index
6614        self._advance()
6615        for keywords in continuations or []:
6616            if isinstance(keywords, str):
6617                keywords = (keywords,)
6618
6619            if self._match_text_seq(*keywords):
6620                option = f"{option} {' '.join(keywords)}"
6621                break
6622        else:
6623            if continuations or continuations is None:
6624                if raise_unmatched:
6625                    self.raise_error(f"Unknown option {option}")
6626
6627                self._retreat(index)
6628                return None
6629
6630        return exp.var(option)
6631
6632    def _parse_as_command(self, start: Token) -> exp.Command:
6633        while self._curr:
6634            self._advance()
6635        text = self._find_sql(start, self._prev)
6636        size = len(start.text)
6637        self._warn_unsupported()
6638        return exp.Command(this=text[:size], expression=text[size:])
6639
6640    def _parse_dict_property(self, this: str) -> exp.DictProperty:
6641        settings = []
6642
6643        self._match_l_paren()
6644        kind = self._parse_id_var()
6645
6646        if self._match(TokenType.L_PAREN):
6647            while True:
6648                key = self._parse_id_var()
6649                value = self._parse_primary()
6650
6651                if not key and value is None:
6652                    break
6653                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
6654            self._match(TokenType.R_PAREN)
6655
6656        self._match_r_paren()
6657
6658        return self.expression(
6659            exp.DictProperty,
6660            this=this,
6661            kind=kind.this if kind else None,
6662            settings=settings,
6663        )
6664
6665    def _parse_dict_range(self, this: str) -> exp.DictRange:
6666        self._match_l_paren()
6667        has_min = self._match_text_seq("MIN")
6668        if has_min:
6669            min = self._parse_var() or self._parse_primary()
6670            self._match_text_seq("MAX")
6671            max = self._parse_var() or self._parse_primary()
6672        else:
6673            max = self._parse_var() or self._parse_primary()
6674            min = exp.Literal.number(0)
6675        self._match_r_paren()
6676        return self.expression(exp.DictRange, this=this, min=min, max=max)
6677
6678    def _parse_comprehension(
6679        self, this: t.Optional[exp.Expression]
6680    ) -> t.Optional[exp.Comprehension]:
6681        index = self._index
6682        expression = self._parse_column()
6683        if not self._match(TokenType.IN):
6684            self._retreat(index - 1)
6685            return None
6686        iterator = self._parse_column()
6687        condition = self._parse_assignment() if self._match_text_seq("IF") else None
6688        return self.expression(
6689            exp.Comprehension,
6690            this=this,
6691            expression=expression,
6692            iterator=iterator,
6693            condition=condition,
6694        )
6695
6696    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
6697        if self._match(TokenType.HEREDOC_STRING):
6698            return self.expression(exp.Heredoc, this=self._prev.text)
6699
6700        if not self._match_text_seq("$"):
6701            return None
6702
6703        tags = ["$"]
6704        tag_text = None
6705
6706        if self._is_connected():
6707            self._advance()
6708            tags.append(self._prev.text.upper())
6709        else:
6710            self.raise_error("No closing $ found")
6711
6712        if tags[-1] != "$":
6713            if self._is_connected() and self._match_text_seq("$"):
6714                tag_text = tags[-1]
6715                tags.append("$")
6716            else:
6717                self.raise_error("No closing $ found")
6718
6719        heredoc_start = self._curr
6720
6721        while self._curr:
6722            if self._match_text_seq(*tags, advance=False):
6723                this = self._find_sql(heredoc_start, self._prev)
6724                self._advance(len(tags))
6725                return self.expression(exp.Heredoc, this=this, tag=tag_text)
6726
6727            self._advance()
6728
6729        self.raise_error(f"No closing {''.join(tags)} found")
6730        return None
6731
6732    def _find_parser(
6733        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
6734    ) -> t.Optional[t.Callable]:
6735        if not self._curr:
6736            return None
6737
6738        index = self._index
6739        this = []
6740        while True:
6741            # The current token might be multiple words
6742            curr = self._curr.text.upper()
6743            key = curr.split(" ")
6744            this.append(curr)
6745
6746            self._advance()
6747            result, trie = in_trie(trie, key)
6748            if result == TrieResult.FAILED:
6749                break
6750
6751            if result == TrieResult.EXISTS:
6752                subparser = parsers[" ".join(this)]
6753                return subparser
6754
6755        self._retreat(index)
6756        return None
6757
6758    def _match(self, token_type, advance=True, expression=None):
6759        if not self._curr:
6760            return None
6761
6762        if self._curr.token_type == token_type:
6763            if advance:
6764                self._advance()
6765            self._add_comments(expression)
6766            return True
6767
6768        return None
6769
6770    def _match_set(self, types, advance=True):
6771        if not self._curr:
6772            return None
6773
6774        if self._curr.token_type in types:
6775            if advance:
6776                self._advance()
6777            return True
6778
6779        return None
6780
6781    def _match_pair(self, token_type_a, token_type_b, advance=True):
6782        if not self._curr or not self._next:
6783            return None
6784
6785        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
6786            if advance:
6787                self._advance(2)
6788            return True
6789
6790        return None
6791
6792    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
6793        if not self._match(TokenType.L_PAREN, expression=expression):
6794            self.raise_error("Expecting (")
6795
6796    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
6797        if not self._match(TokenType.R_PAREN, expression=expression):
6798            self.raise_error("Expecting )")
6799
6800    def _match_texts(self, texts, advance=True):
6801        if self._curr and self._curr.text.upper() in texts:
6802            if advance:
6803                self._advance()
6804            return True
6805        return None
6806
6807    def _match_text_seq(self, *texts, advance=True):
6808        index = self._index
6809        for text in texts:
6810            if self._curr and self._curr.text.upper() == text:
6811                self._advance()
6812            else:
6813                self._retreat(index)
6814                return None
6815
6816        if not advance:
6817            self._retreat(index)
6818
6819        return True
6820
6821    def _replace_lambda(
6822        self, node: t.Optional[exp.Expression], expressions: t.List[exp.Expression]
6823    ) -> t.Optional[exp.Expression]:
6824        if not node:
6825            return node
6826
6827        lambda_types = {e.name: e.args.get("to") or False for e in expressions}
6828
6829        for column in node.find_all(exp.Column):
6830            typ = lambda_types.get(column.parts[0].name)
6831            if typ is not None:
6832                dot_or_id = column.to_dot() if column.table else column.this
6833
6834                if typ:
6835                    dot_or_id = self.expression(
6836                        exp.Cast,
6837                        this=dot_or_id,
6838                        to=typ,
6839                    )
6840
6841                parent = column.parent
6842
6843                while isinstance(parent, exp.Dot):
6844                    if not isinstance(parent.parent, exp.Dot):
6845                        parent.replace(dot_or_id)
6846                        break
6847                    parent = parent.parent
6848                else:
6849                    if column is node:
6850                        node = dot_or_id
6851                    else:
6852                        column.replace(dot_or_id)
6853        return node
6854
6855    def _parse_truncate_table(self) -> t.Optional[exp.TruncateTable] | exp.Expression:
6856        start = self._prev
6857
6858        # Not to be confused with TRUNCATE(number, decimals) function call
6859        if self._match(TokenType.L_PAREN):
6860            self._retreat(self._index - 2)
6861            return self._parse_function()
6862
6863        # Clickhouse supports TRUNCATE DATABASE as well
6864        is_database = self._match(TokenType.DATABASE)
6865
6866        self._match(TokenType.TABLE)
6867
6868        exists = self._parse_exists(not_=False)
6869
6870        expressions = self._parse_csv(
6871            lambda: self._parse_table(schema=True, is_db_reference=is_database)
6872        )
6873
6874        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
6875
6876        if self._match_text_seq("RESTART", "IDENTITY"):
6877            identity = "RESTART"
6878        elif self._match_text_seq("CONTINUE", "IDENTITY"):
6879            identity = "CONTINUE"
6880        else:
6881            identity = None
6882
6883        if self._match_text_seq("CASCADE") or self._match_text_seq("RESTRICT"):
6884            option = self._prev.text
6885        else:
6886            option = None
6887
6888        partition = self._parse_partition()
6889
6890        # Fallback case
6891        if self._curr:
6892            return self._parse_as_command(start)
6893
6894        return self.expression(
6895            exp.TruncateTable,
6896            expressions=expressions,
6897            is_database=is_database,
6898            exists=exists,
6899            cluster=cluster,
6900            identity=identity,
6901            option=option,
6902            partition=partition,
6903        )
6904
6905    def _parse_with_operator(self) -> t.Optional[exp.Expression]:
6906        this = self._parse_ordered(self._parse_opclass)
6907
6908        if not self._match(TokenType.WITH):
6909            return this
6910
6911        op = self._parse_var(any_token=True)
6912
6913        return self.expression(exp.WithOperator, this=this, op=op)
6914
6915    def _parse_wrapped_options(self) -> t.List[t.Optional[exp.Expression]]:
6916        self._match(TokenType.EQ)
6917        self._match(TokenType.L_PAREN)
6918
6919        opts: t.List[t.Optional[exp.Expression]] = []
6920        while self._curr and not self._match(TokenType.R_PAREN):
6921            if self._match_text_seq("FORMAT_NAME", "="):
6922                # The FORMAT_NAME can be set to an identifier for Snowflake and T-SQL,
6923                # so we parse it separately to use _parse_field()
6924                prop = self.expression(
6925                    exp.Property, this=exp.var("FORMAT_NAME"), value=self._parse_field()
6926                )
6927                opts.append(prop)
6928            else:
6929                opts.append(self._parse_property())
6930
6931            self._match(TokenType.COMMA)
6932
6933        return opts
6934
6935    def _parse_copy_parameters(self) -> t.List[exp.CopyParameter]:
6936        sep = TokenType.COMMA if self.dialect.COPY_PARAMS_ARE_CSV else None
6937
6938        options = []
6939        while self._curr and not self._match(TokenType.R_PAREN, advance=False):
6940            option = self._parse_var(any_token=True)
6941            prev = self._prev.text.upper()
6942
6943            # Different dialects might separate options and values by white space, "=" and "AS"
6944            self._match(TokenType.EQ)
6945            self._match(TokenType.ALIAS)
6946
6947            param = self.expression(exp.CopyParameter, this=option)
6948
6949            if prev in self.COPY_INTO_VARLEN_OPTIONS and self._match(
6950                TokenType.L_PAREN, advance=False
6951            ):
6952                # Snowflake FILE_FORMAT case, Databricks COPY & FORMAT options
6953                param.set("expressions", self._parse_wrapped_options())
6954            elif prev == "FILE_FORMAT":
6955                # T-SQL's external file format case
6956                param.set("expression", self._parse_field())
6957            else:
6958                param.set("expression", self._parse_unquoted_field())
6959
6960            options.append(param)
6961            self._match(sep)
6962
6963        return options
6964
6965    def _parse_credentials(self) -> t.Optional[exp.Credentials]:
6966        expr = self.expression(exp.Credentials)
6967
6968        if self._match_text_seq("STORAGE_INTEGRATION", "="):
6969            expr.set("storage", self._parse_field())
6970        if self._match_text_seq("CREDENTIALS"):
6971            # Snowflake case: CREDENTIALS = (...), Redshift case: CREDENTIALS <string>
6972            creds = (
6973                self._parse_wrapped_options() if self._match(TokenType.EQ) else self._parse_field()
6974            )
6975            expr.set("credentials", creds)
6976        if self._match_text_seq("ENCRYPTION"):
6977            expr.set("encryption", self._parse_wrapped_options())
6978        if self._match_text_seq("IAM_ROLE"):
6979            expr.set("iam_role", self._parse_field())
6980        if self._match_text_seq("REGION"):
6981            expr.set("region", self._parse_field())
6982
6983        return expr
6984
6985    def _parse_file_location(self) -> t.Optional[exp.Expression]:
6986        return self._parse_field()
6987
6988    def _parse_copy(self) -> exp.Copy | exp.Command:
6989        start = self._prev
6990
6991        self._match(TokenType.INTO)
6992
6993        this = (
6994            self._parse_select(nested=True, parse_subquery_alias=False)
6995            if self._match(TokenType.L_PAREN, advance=False)
6996            else self._parse_table(schema=True)
6997        )
6998
6999        kind = self._match(TokenType.FROM) or not self._match_text_seq("TO")
7000
7001        files = self._parse_csv(self._parse_file_location)
7002        credentials = self._parse_credentials()
7003
7004        self._match_text_seq("WITH")
7005
7006        params = self._parse_wrapped(self._parse_copy_parameters, optional=True)
7007
7008        # Fallback case
7009        if self._curr:
7010            return self._parse_as_command(start)
7011
7012        return self.expression(
7013            exp.Copy,
7014            this=this,
7015            kind=kind,
7016            credentials=credentials,
7017            files=files,
7018            params=params,
7019        )
logger = <Logger sqlglot (WARNING)>
OPTIONS_TYPE = typing.Dict[str, typing.Sequence[typing.Union[typing.Sequence[str], str]]]
def build_var_map(args: List) -> sqlglot.expressions.StarMap | sqlglot.expressions.VarMap:
26def build_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
27    if len(args) == 1 and args[0].is_star:
28        return exp.StarMap(this=args[0])
29
30    keys = []
31    values = []
32    for i in range(0, len(args), 2):
33        keys.append(args[i])
34        values.append(args[i + 1])
35
36    return exp.VarMap(keys=exp.array(*keys, copy=False), values=exp.array(*values, copy=False))
def build_like(args: List) -> sqlglot.expressions.Escape | sqlglot.expressions.Like:
39def build_like(args: t.List) -> exp.Escape | exp.Like:
40    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
41    return exp.Escape(this=like, expression=seq_get(args, 2)) if len(args) > 2 else like
def binary_range_parser( expr_type: Type[sqlglot.expressions.Expression], reverse_args: bool = False) -> Callable[[Parser, Optional[sqlglot.expressions.Expression]], Optional[sqlglot.expressions.Expression]]:
44def binary_range_parser(
45    expr_type: t.Type[exp.Expression], reverse_args: bool = False
46) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
47    def _parse_binary_range(
48        self: Parser, this: t.Optional[exp.Expression]
49    ) -> t.Optional[exp.Expression]:
50        expression = self._parse_bitwise()
51        if reverse_args:
52            this, expression = expression, this
53        return self._parse_escape(self.expression(expr_type, this=this, expression=expression))
54
55    return _parse_binary_range
def build_logarithm( args: List, dialect: sqlglot.dialects.dialect.Dialect) -> sqlglot.expressions.Func:
58def build_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
59    # Default argument order is base, expression
60    this = seq_get(args, 0)
61    expression = seq_get(args, 1)
62
63    if expression:
64        if not dialect.LOG_BASE_FIRST:
65            this, expression = expression, this
66        return exp.Log(this=this, expression=expression)
67
68    return (exp.Ln if dialect.parser_class.LOG_DEFAULTS_TO_LN else exp.Log)(this=this)
def build_hex( args: List, dialect: sqlglot.dialects.dialect.Dialect) -> sqlglot.expressions.Hex | sqlglot.expressions.LowerHex:
71def build_hex(args: t.List, dialect: Dialect) -> exp.Hex | exp.LowerHex:
72    arg = seq_get(args, 0)
73    return exp.LowerHex(this=arg) if dialect.HEX_LOWERCASE else exp.Hex(this=arg)
def build_lower(args: List) -> sqlglot.expressions.Lower | sqlglot.expressions.Hex:
76def build_lower(args: t.List) -> exp.Lower | exp.Hex:
77    # LOWER(HEX(..)) can be simplified to LowerHex to simplify its transpilation
78    arg = seq_get(args, 0)
79    return exp.LowerHex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Lower(this=arg)
def build_upper(args: List) -> sqlglot.expressions.Upper | sqlglot.expressions.Hex:
82def build_upper(args: t.List) -> exp.Upper | exp.Hex:
83    # UPPER(HEX(..)) can be simplified to Hex to simplify its transpilation
84    arg = seq_get(args, 0)
85    return exp.Hex(this=arg.this) if isinstance(arg, exp.Hex) else exp.Upper(this=arg)
def build_extract_json_with_path( expr_type: Type[~E]) -> Callable[[List, sqlglot.dialects.dialect.Dialect], ~E]:
88def build_extract_json_with_path(expr_type: t.Type[E]) -> t.Callable[[t.List, Dialect], E]:
89    def _builder(args: t.List, dialect: Dialect) -> E:
90        expression = expr_type(
91            this=seq_get(args, 0), expression=dialect.to_json_path(seq_get(args, 1))
92        )
93        if len(args) > 2 and expr_type is exp.JSONExtract:
94            expression.set("expressions", args[2:])
95
96        return expression
97
98    return _builder
def build_mod(args: List) -> sqlglot.expressions.Mod:
101def build_mod(args: t.List) -> exp.Mod:
102    this = seq_get(args, 0)
103    expression = seq_get(args, 1)
104
105    # Wrap the operands if they are binary nodes, e.g. MOD(a + 1, 7) -> (a + 1) % 7
106    this = exp.Paren(this=this) if isinstance(this, exp.Binary) else this
107    expression = exp.Paren(this=expression) if isinstance(expression, exp.Binary) else expression
108
109    return exp.Mod(this=this, expression=expression)
def build_pad(args: List, is_left: bool = True):
112def build_pad(args: t.List, is_left: bool = True):
113    return exp.Pad(
114        this=seq_get(args, 0),
115        expression=seq_get(args, 1),
116        fill_pattern=seq_get(args, 2),
117        is_left=is_left,
118    )
class Parser:
 131class Parser(metaclass=_Parser):
 132    """
 133    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
 134
 135    Args:
 136        error_level: The desired error level.
 137            Default: ErrorLevel.IMMEDIATE
 138        error_message_context: The amount of context to capture from a query string when displaying
 139            the error message (in number of characters).
 140            Default: 100
 141        max_errors: Maximum number of error messages to include in a raised ParseError.
 142            This is only relevant if error_level is ErrorLevel.RAISE.
 143            Default: 3
 144    """
 145
 146    FUNCTIONS: t.Dict[str, t.Callable] = {
 147        **{name: func.from_arg_list for name, func in exp.FUNCTION_BY_NAME.items()},
 148        "CONCAT": lambda args, dialect: exp.Concat(
 149            expressions=args,
 150            safe=not dialect.STRICT_STRING_CONCAT,
 151            coalesce=dialect.CONCAT_COALESCE,
 152        ),
 153        "CONCAT_WS": lambda args, dialect: exp.ConcatWs(
 154            expressions=args,
 155            safe=not dialect.STRICT_STRING_CONCAT,
 156            coalesce=dialect.CONCAT_COALESCE,
 157        ),
 158        "DATE_TO_DATE_STR": lambda args: exp.Cast(
 159            this=seq_get(args, 0),
 160            to=exp.DataType(this=exp.DataType.Type.TEXT),
 161        ),
 162        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
 163        "HEX": build_hex,
 164        "JSON_EXTRACT": build_extract_json_with_path(exp.JSONExtract),
 165        "JSON_EXTRACT_SCALAR": build_extract_json_with_path(exp.JSONExtractScalar),
 166        "JSON_EXTRACT_PATH_TEXT": build_extract_json_with_path(exp.JSONExtractScalar),
 167        "LIKE": build_like,
 168        "LOG": build_logarithm,
 169        "LOG2": lambda args: exp.Log(this=exp.Literal.number(2), expression=seq_get(args, 0)),
 170        "LOG10": lambda args: exp.Log(this=exp.Literal.number(10), expression=seq_get(args, 0)),
 171        "LOWER": build_lower,
 172        "LPAD": lambda args: build_pad(args),
 173        "LEFTPAD": lambda args: build_pad(args),
 174        "MOD": build_mod,
 175        "RPAD": lambda args: build_pad(args, is_left=False),
 176        "RIGHTPAD": lambda args: build_pad(args, is_left=False),
 177        "SCOPE_RESOLUTION": lambda args: exp.ScopeResolution(expression=seq_get(args, 0))
 178        if len(args) != 2
 179        else exp.ScopeResolution(this=seq_get(args, 0), expression=seq_get(args, 1)),
 180        "TIME_TO_TIME_STR": lambda args: exp.Cast(
 181            this=seq_get(args, 0),
 182            to=exp.DataType(this=exp.DataType.Type.TEXT),
 183        ),
 184        "TO_HEX": build_hex,
 185        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
 186            this=exp.Cast(
 187                this=seq_get(args, 0),
 188                to=exp.DataType(this=exp.DataType.Type.TEXT),
 189            ),
 190            start=exp.Literal.number(1),
 191            length=exp.Literal.number(10),
 192        ),
 193        "UNNEST": lambda args: exp.Unnest(expressions=ensure_list(seq_get(args, 0))),
 194        "UPPER": build_upper,
 195        "VAR_MAP": build_var_map,
 196    }
 197
 198    NO_PAREN_FUNCTIONS = {
 199        TokenType.CURRENT_DATE: exp.CurrentDate,
 200        TokenType.CURRENT_DATETIME: exp.CurrentDate,
 201        TokenType.CURRENT_TIME: exp.CurrentTime,
 202        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
 203        TokenType.CURRENT_USER: exp.CurrentUser,
 204    }
 205
 206    STRUCT_TYPE_TOKENS = {
 207        TokenType.NESTED,
 208        TokenType.OBJECT,
 209        TokenType.STRUCT,
 210    }
 211
 212    NESTED_TYPE_TOKENS = {
 213        TokenType.ARRAY,
 214        TokenType.LIST,
 215        TokenType.LOWCARDINALITY,
 216        TokenType.MAP,
 217        TokenType.NULLABLE,
 218        *STRUCT_TYPE_TOKENS,
 219    }
 220
 221    ENUM_TYPE_TOKENS = {
 222        TokenType.ENUM,
 223        TokenType.ENUM8,
 224        TokenType.ENUM16,
 225    }
 226
 227    AGGREGATE_TYPE_TOKENS = {
 228        TokenType.AGGREGATEFUNCTION,
 229        TokenType.SIMPLEAGGREGATEFUNCTION,
 230    }
 231
 232    TYPE_TOKENS = {
 233        TokenType.BIT,
 234        TokenType.BOOLEAN,
 235        TokenType.TINYINT,
 236        TokenType.UTINYINT,
 237        TokenType.SMALLINT,
 238        TokenType.USMALLINT,
 239        TokenType.INT,
 240        TokenType.UINT,
 241        TokenType.BIGINT,
 242        TokenType.UBIGINT,
 243        TokenType.INT128,
 244        TokenType.UINT128,
 245        TokenType.INT256,
 246        TokenType.UINT256,
 247        TokenType.MEDIUMINT,
 248        TokenType.UMEDIUMINT,
 249        TokenType.FIXEDSTRING,
 250        TokenType.FLOAT,
 251        TokenType.DOUBLE,
 252        TokenType.CHAR,
 253        TokenType.NCHAR,
 254        TokenType.VARCHAR,
 255        TokenType.NVARCHAR,
 256        TokenType.BPCHAR,
 257        TokenType.TEXT,
 258        TokenType.MEDIUMTEXT,
 259        TokenType.LONGTEXT,
 260        TokenType.MEDIUMBLOB,
 261        TokenType.LONGBLOB,
 262        TokenType.BINARY,
 263        TokenType.VARBINARY,
 264        TokenType.JSON,
 265        TokenType.JSONB,
 266        TokenType.INTERVAL,
 267        TokenType.TINYBLOB,
 268        TokenType.TINYTEXT,
 269        TokenType.TIME,
 270        TokenType.TIMETZ,
 271        TokenType.TIMESTAMP,
 272        TokenType.TIMESTAMP_S,
 273        TokenType.TIMESTAMP_MS,
 274        TokenType.TIMESTAMP_NS,
 275        TokenType.TIMESTAMPTZ,
 276        TokenType.TIMESTAMPLTZ,
 277        TokenType.TIMESTAMPNTZ,
 278        TokenType.DATETIME,
 279        TokenType.DATETIME64,
 280        TokenType.DATE,
 281        TokenType.DATE32,
 282        TokenType.INT4RANGE,
 283        TokenType.INT4MULTIRANGE,
 284        TokenType.INT8RANGE,
 285        TokenType.INT8MULTIRANGE,
 286        TokenType.NUMRANGE,
 287        TokenType.NUMMULTIRANGE,
 288        TokenType.TSRANGE,
 289        TokenType.TSMULTIRANGE,
 290        TokenType.TSTZRANGE,
 291        TokenType.TSTZMULTIRANGE,
 292        TokenType.DATERANGE,
 293        TokenType.DATEMULTIRANGE,
 294        TokenType.DECIMAL,
 295        TokenType.UDECIMAL,
 296        TokenType.BIGDECIMAL,
 297        TokenType.UUID,
 298        TokenType.GEOGRAPHY,
 299        TokenType.GEOMETRY,
 300        TokenType.HLLSKETCH,
 301        TokenType.HSTORE,
 302        TokenType.PSEUDO_TYPE,
 303        TokenType.SUPER,
 304        TokenType.SERIAL,
 305        TokenType.SMALLSERIAL,
 306        TokenType.BIGSERIAL,
 307        TokenType.XML,
 308        TokenType.YEAR,
 309        TokenType.UNIQUEIDENTIFIER,
 310        TokenType.USERDEFINED,
 311        TokenType.MONEY,
 312        TokenType.SMALLMONEY,
 313        TokenType.ROWVERSION,
 314        TokenType.IMAGE,
 315        TokenType.VARIANT,
 316        TokenType.VECTOR,
 317        TokenType.OBJECT,
 318        TokenType.OBJECT_IDENTIFIER,
 319        TokenType.INET,
 320        TokenType.IPADDRESS,
 321        TokenType.IPPREFIX,
 322        TokenType.IPV4,
 323        TokenType.IPV6,
 324        TokenType.UNKNOWN,
 325        TokenType.NULL,
 326        TokenType.NAME,
 327        TokenType.TDIGEST,
 328        *ENUM_TYPE_TOKENS,
 329        *NESTED_TYPE_TOKENS,
 330        *AGGREGATE_TYPE_TOKENS,
 331    }
 332
 333    SIGNED_TO_UNSIGNED_TYPE_TOKEN = {
 334        TokenType.BIGINT: TokenType.UBIGINT,
 335        TokenType.INT: TokenType.UINT,
 336        TokenType.MEDIUMINT: TokenType.UMEDIUMINT,
 337        TokenType.SMALLINT: TokenType.USMALLINT,
 338        TokenType.TINYINT: TokenType.UTINYINT,
 339        TokenType.DECIMAL: TokenType.UDECIMAL,
 340    }
 341
 342    SUBQUERY_PREDICATES = {
 343        TokenType.ANY: exp.Any,
 344        TokenType.ALL: exp.All,
 345        TokenType.EXISTS: exp.Exists,
 346        TokenType.SOME: exp.Any,
 347    }
 348
 349    RESERVED_TOKENS = {
 350        *Tokenizer.SINGLE_TOKENS.values(),
 351        TokenType.SELECT,
 352    } - {TokenType.IDENTIFIER}
 353
 354    DB_CREATABLES = {
 355        TokenType.DATABASE,
 356        TokenType.DICTIONARY,
 357        TokenType.MODEL,
 358        TokenType.SCHEMA,
 359        TokenType.SEQUENCE,
 360        TokenType.STORAGE_INTEGRATION,
 361        TokenType.TABLE,
 362        TokenType.TAG,
 363        TokenType.VIEW,
 364        TokenType.WAREHOUSE,
 365        TokenType.STREAMLIT,
 366    }
 367
 368    CREATABLES = {
 369        TokenType.COLUMN,
 370        TokenType.CONSTRAINT,
 371        TokenType.FOREIGN_KEY,
 372        TokenType.FUNCTION,
 373        TokenType.INDEX,
 374        TokenType.PROCEDURE,
 375        *DB_CREATABLES,
 376    }
 377
 378    # Tokens that can represent identifiers
 379    ID_VAR_TOKENS = {
 380        TokenType.ALL,
 381        TokenType.VAR,
 382        TokenType.ANTI,
 383        TokenType.APPLY,
 384        TokenType.ASC,
 385        TokenType.ASOF,
 386        TokenType.AUTO_INCREMENT,
 387        TokenType.BEGIN,
 388        TokenType.BPCHAR,
 389        TokenType.CACHE,
 390        TokenType.CASE,
 391        TokenType.COLLATE,
 392        TokenType.COMMAND,
 393        TokenType.COMMENT,
 394        TokenType.COMMIT,
 395        TokenType.CONSTRAINT,
 396        TokenType.COPY,
 397        TokenType.CUBE,
 398        TokenType.DEFAULT,
 399        TokenType.DELETE,
 400        TokenType.DESC,
 401        TokenType.DESCRIBE,
 402        TokenType.DICTIONARY,
 403        TokenType.DIV,
 404        TokenType.END,
 405        TokenType.EXECUTE,
 406        TokenType.ESCAPE,
 407        TokenType.FALSE,
 408        TokenType.FIRST,
 409        TokenType.FILTER,
 410        TokenType.FINAL,
 411        TokenType.FORMAT,
 412        TokenType.FULL,
 413        TokenType.IDENTIFIER,
 414        TokenType.IS,
 415        TokenType.ISNULL,
 416        TokenType.INTERVAL,
 417        TokenType.KEEP,
 418        TokenType.KILL,
 419        TokenType.LEFT,
 420        TokenType.LOAD,
 421        TokenType.MERGE,
 422        TokenType.NATURAL,
 423        TokenType.NEXT,
 424        TokenType.OFFSET,
 425        TokenType.OPERATOR,
 426        TokenType.ORDINALITY,
 427        TokenType.OVERLAPS,
 428        TokenType.OVERWRITE,
 429        TokenType.PARTITION,
 430        TokenType.PERCENT,
 431        TokenType.PIVOT,
 432        TokenType.PRAGMA,
 433        TokenType.RANGE,
 434        TokenType.RECURSIVE,
 435        TokenType.REFERENCES,
 436        TokenType.REFRESH,
 437        TokenType.REPLACE,
 438        TokenType.RIGHT,
 439        TokenType.ROLLUP,
 440        TokenType.ROW,
 441        TokenType.ROWS,
 442        TokenType.SEMI,
 443        TokenType.SET,
 444        TokenType.SETTINGS,
 445        TokenType.SHOW,
 446        TokenType.TEMPORARY,
 447        TokenType.TOP,
 448        TokenType.TRUE,
 449        TokenType.TRUNCATE,
 450        TokenType.UNIQUE,
 451        TokenType.UNNEST,
 452        TokenType.UNPIVOT,
 453        TokenType.UPDATE,
 454        TokenType.USE,
 455        TokenType.VOLATILE,
 456        TokenType.WINDOW,
 457        *CREATABLES,
 458        *SUBQUERY_PREDICATES,
 459        *TYPE_TOKENS,
 460        *NO_PAREN_FUNCTIONS,
 461    }
 462
 463    INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
 464
 465    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
 466        TokenType.ANTI,
 467        TokenType.APPLY,
 468        TokenType.ASOF,
 469        TokenType.FULL,
 470        TokenType.LEFT,
 471        TokenType.LOCK,
 472        TokenType.NATURAL,
 473        TokenType.OFFSET,
 474        TokenType.RIGHT,
 475        TokenType.SEMI,
 476        TokenType.WINDOW,
 477    }
 478
 479    ALIAS_TOKENS = ID_VAR_TOKENS
 480
 481    ARRAY_CONSTRUCTORS = {
 482        "ARRAY": exp.Array,
 483        "LIST": exp.List,
 484    }
 485
 486    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
 487
 488    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
 489
 490    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
 491
 492    FUNC_TOKENS = {
 493        TokenType.COLLATE,
 494        TokenType.COMMAND,
 495        TokenType.CURRENT_DATE,
 496        TokenType.CURRENT_DATETIME,
 497        TokenType.CURRENT_TIMESTAMP,
 498        TokenType.CURRENT_TIME,
 499        TokenType.CURRENT_USER,
 500        TokenType.FILTER,
 501        TokenType.FIRST,
 502        TokenType.FORMAT,
 503        TokenType.GLOB,
 504        TokenType.IDENTIFIER,
 505        TokenType.INDEX,
 506        TokenType.ISNULL,
 507        TokenType.ILIKE,
 508        TokenType.INSERT,
 509        TokenType.LIKE,
 510        TokenType.MERGE,
 511        TokenType.OFFSET,
 512        TokenType.PRIMARY_KEY,
 513        TokenType.RANGE,
 514        TokenType.REPLACE,
 515        TokenType.RLIKE,
 516        TokenType.ROW,
 517        TokenType.UNNEST,
 518        TokenType.VAR,
 519        TokenType.LEFT,
 520        TokenType.RIGHT,
 521        TokenType.SEQUENCE,
 522        TokenType.DATE,
 523        TokenType.DATETIME,
 524        TokenType.TABLE,
 525        TokenType.TIMESTAMP,
 526        TokenType.TIMESTAMPTZ,
 527        TokenType.TRUNCATE,
 528        TokenType.WINDOW,
 529        TokenType.XOR,
 530        *TYPE_TOKENS,
 531        *SUBQUERY_PREDICATES,
 532    }
 533
 534    CONJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
 535        TokenType.AND: exp.And,
 536    }
 537
 538    ASSIGNMENT: t.Dict[TokenType, t.Type[exp.Expression]] = {
 539        TokenType.COLON_EQ: exp.PropertyEQ,
 540    }
 541
 542    DISJUNCTION: t.Dict[TokenType, t.Type[exp.Expression]] = {
 543        TokenType.OR: exp.Or,
 544    }
 545
 546    EQUALITY = {
 547        TokenType.EQ: exp.EQ,
 548        TokenType.NEQ: exp.NEQ,
 549        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
 550    }
 551
 552    COMPARISON = {
 553        TokenType.GT: exp.GT,
 554        TokenType.GTE: exp.GTE,
 555        TokenType.LT: exp.LT,
 556        TokenType.LTE: exp.LTE,
 557    }
 558
 559    BITWISE = {
 560        TokenType.AMP: exp.BitwiseAnd,
 561        TokenType.CARET: exp.BitwiseXor,
 562        TokenType.PIPE: exp.BitwiseOr,
 563    }
 564
 565    TERM = {
 566        TokenType.DASH: exp.Sub,
 567        TokenType.PLUS: exp.Add,
 568        TokenType.MOD: exp.Mod,
 569        TokenType.COLLATE: exp.Collate,
 570    }
 571
 572    FACTOR = {
 573        TokenType.DIV: exp.IntDiv,
 574        TokenType.LR_ARROW: exp.Distance,
 575        TokenType.SLASH: exp.Div,
 576        TokenType.STAR: exp.Mul,
 577    }
 578
 579    EXPONENT: t.Dict[TokenType, t.Type[exp.Expression]] = {}
 580
 581    TIMES = {
 582        TokenType.TIME,
 583        TokenType.TIMETZ,
 584    }
 585
 586    TIMESTAMPS = {
 587        TokenType.TIMESTAMP,
 588        TokenType.TIMESTAMPTZ,
 589        TokenType.TIMESTAMPLTZ,
 590        *TIMES,
 591    }
 592
 593    SET_OPERATIONS = {
 594        TokenType.UNION,
 595        TokenType.INTERSECT,
 596        TokenType.EXCEPT,
 597    }
 598
 599    JOIN_METHODS = {
 600        TokenType.ASOF,
 601        TokenType.NATURAL,
 602        TokenType.POSITIONAL,
 603    }
 604
 605    JOIN_SIDES = {
 606        TokenType.LEFT,
 607        TokenType.RIGHT,
 608        TokenType.FULL,
 609    }
 610
 611    JOIN_KINDS = {
 612        TokenType.ANTI,
 613        TokenType.CROSS,
 614        TokenType.INNER,
 615        TokenType.OUTER,
 616        TokenType.SEMI,
 617        TokenType.STRAIGHT_JOIN,
 618    }
 619
 620    JOIN_HINTS: t.Set[str] = set()
 621
 622    LAMBDAS = {
 623        TokenType.ARROW: lambda self, expressions: self.expression(
 624            exp.Lambda,
 625            this=self._replace_lambda(
 626                self._parse_assignment(),
 627                expressions,
 628            ),
 629            expressions=expressions,
 630        ),
 631        TokenType.FARROW: lambda self, expressions: self.expression(
 632            exp.Kwarg,
 633            this=exp.var(expressions[0].name),
 634            expression=self._parse_assignment(),
 635        ),
 636    }
 637
 638    COLUMN_OPERATORS = {
 639        TokenType.DOT: None,
 640        TokenType.DCOLON: lambda self, this, to: self.expression(
 641            exp.Cast if self.STRICT_CAST else exp.TryCast,
 642            this=this,
 643            to=to,
 644        ),
 645        TokenType.ARROW: lambda self, this, path: self.expression(
 646            exp.JSONExtract,
 647            this=this,
 648            expression=self.dialect.to_json_path(path),
 649            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
 650        ),
 651        TokenType.DARROW: lambda self, this, path: self.expression(
 652            exp.JSONExtractScalar,
 653            this=this,
 654            expression=self.dialect.to_json_path(path),
 655            only_json_types=self.JSON_ARROWS_REQUIRE_JSON_TYPE,
 656        ),
 657        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
 658            exp.JSONBExtract,
 659            this=this,
 660            expression=path,
 661        ),
 662        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
 663            exp.JSONBExtractScalar,
 664            this=this,
 665            expression=path,
 666        ),
 667        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
 668            exp.JSONBContains,
 669            this=this,
 670            expression=key,
 671        ),
 672    }
 673
 674    EXPRESSION_PARSERS = {
 675        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
 676        exp.Column: lambda self: self._parse_column(),
 677        exp.Condition: lambda self: self._parse_assignment(),
 678        exp.DataType: lambda self: self._parse_types(allow_identifiers=False, schema=True),
 679        exp.Expression: lambda self: self._parse_expression(),
 680        exp.From: lambda self: self._parse_from(joins=True),
 681        exp.Group: lambda self: self._parse_group(),
 682        exp.Having: lambda self: self._parse_having(),
 683        exp.Identifier: lambda self: self._parse_id_var(),
 684        exp.Join: lambda self: self._parse_join(),
 685        exp.Lambda: lambda self: self._parse_lambda(),
 686        exp.Lateral: lambda self: self._parse_lateral(),
 687        exp.Limit: lambda self: self._parse_limit(),
 688        exp.Offset: lambda self: self._parse_offset(),
 689        exp.Order: lambda self: self._parse_order(),
 690        exp.Ordered: lambda self: self._parse_ordered(),
 691        exp.Properties: lambda self: self._parse_properties(),
 692        exp.Qualify: lambda self: self._parse_qualify(),
 693        exp.Returning: lambda self: self._parse_returning(),
 694        exp.Select: lambda self: self._parse_select(),
 695        exp.Sort: lambda self: self._parse_sort(exp.Sort, TokenType.SORT_BY),
 696        exp.Table: lambda self: self._parse_table_parts(),
 697        exp.TableAlias: lambda self: self._parse_table_alias(),
 698        exp.When: lambda self: seq_get(self._parse_when_matched(), 0),
 699        exp.Where: lambda self: self._parse_where(),
 700        exp.Window: lambda self: self._parse_named_window(),
 701        exp.With: lambda self: self._parse_with(),
 702        "JOIN_TYPE": lambda self: self._parse_join_parts(),
 703    }
 704
 705    STATEMENT_PARSERS = {
 706        TokenType.ALTER: lambda self: self._parse_alter(),
 707        TokenType.BEGIN: lambda self: self._parse_transaction(),
 708        TokenType.CACHE: lambda self: self._parse_cache(),
 709        TokenType.COMMENT: lambda self: self._parse_comment(),
 710        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
 711        TokenType.COPY: lambda self: self._parse_copy(),
 712        TokenType.CREATE: lambda self: self._parse_create(),
 713        TokenType.DELETE: lambda self: self._parse_delete(),
 714        TokenType.DESC: lambda self: self._parse_describe(),
 715        TokenType.DESCRIBE: lambda self: self._parse_describe(),
 716        TokenType.DROP: lambda self: self._parse_drop(),
 717        TokenType.INSERT: lambda self: self._parse_insert(),
 718        TokenType.KILL: lambda self: self._parse_kill(),
 719        TokenType.LOAD: lambda self: self._parse_load(),
 720        TokenType.MERGE: lambda self: self._parse_merge(),
 721        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
 722        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
 723        TokenType.REFRESH: lambda self: self._parse_refresh(),
 724        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
 725        TokenType.SET: lambda self: self._parse_set(),
 726        TokenType.TRUNCATE: lambda self: self._parse_truncate_table(),
 727        TokenType.UNCACHE: lambda self: self._parse_uncache(),
 728        TokenType.UPDATE: lambda self: self._parse_update(),
 729        TokenType.USE: lambda self: self.expression(
 730            exp.Use,
 731            kind=self._parse_var_from_options(self.USABLES, raise_unmatched=False),
 732            this=self._parse_table(schema=False),
 733        ),
 734        TokenType.SEMICOLON: lambda self: self.expression(exp.Semicolon),
 735    }
 736
 737    UNARY_PARSERS = {
 738        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
 739        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
 740        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
 741        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
 742        TokenType.PIPE_SLASH: lambda self: self.expression(exp.Sqrt, this=self._parse_unary()),
 743        TokenType.DPIPE_SLASH: lambda self: self.expression(exp.Cbrt, this=self._parse_unary()),
 744    }
 745
 746    STRING_PARSERS = {
 747        TokenType.HEREDOC_STRING: lambda self, token: self.expression(
 748            exp.RawString, this=token.text
 749        ),
 750        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
 751            exp.National, this=token.text
 752        ),
 753        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
 754        TokenType.STRING: lambda self, token: self.expression(
 755            exp.Literal, this=token.text, is_string=True
 756        ),
 757        TokenType.UNICODE_STRING: lambda self, token: self.expression(
 758            exp.UnicodeString,
 759            this=token.text,
 760            escape=self._match_text_seq("UESCAPE") and self._parse_string(),
 761        ),
 762    }
 763
 764    NUMERIC_PARSERS = {
 765        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
 766        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
 767        TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text),
 768        TokenType.NUMBER: lambda self, token: self.expression(
 769            exp.Literal, this=token.text, is_string=False
 770        ),
 771    }
 772
 773    PRIMARY_PARSERS = {
 774        **STRING_PARSERS,
 775        **NUMERIC_PARSERS,
 776        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
 777        TokenType.NULL: lambda self, _: self.expression(exp.Null),
 778        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
 779        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
 780        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
 781        TokenType.STAR: lambda self, _: self.expression(
 782            exp.Star,
 783            **{
 784                "except": self._parse_star_op("EXCEPT", "EXCLUDE"),
 785                "replace": self._parse_star_op("REPLACE"),
 786                "rename": self._parse_star_op("RENAME"),
 787            },
 788        ),
 789    }
 790
 791    PLACEHOLDER_PARSERS = {
 792        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
 793        TokenType.PARAMETER: lambda self: self._parse_parameter(),
 794        TokenType.COLON: lambda self: (
 795            self.expression(exp.Placeholder, this=self._prev.text)
 796            if self._match_set(self.ID_VAR_TOKENS)
 797            else None
 798        ),
 799    }
 800
 801    RANGE_PARSERS = {
 802        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
 803        TokenType.GLOB: binary_range_parser(exp.Glob),
 804        TokenType.ILIKE: binary_range_parser(exp.ILike),
 805        TokenType.IN: lambda self, this: self._parse_in(this),
 806        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
 807        TokenType.IS: lambda self, this: self._parse_is(this),
 808        TokenType.LIKE: binary_range_parser(exp.Like),
 809        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
 810        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
 811        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
 812        TokenType.FOR: lambda self, this: self._parse_comprehension(this),
 813    }
 814
 815    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
 816        "ALLOWED_VALUES": lambda self: self.expression(
 817            exp.AllowedValuesProperty, expressions=self._parse_csv(self._parse_primary)
 818        ),
 819        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
 820        "AUTO": lambda self: self._parse_auto_property(),
 821        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
 822        "BACKUP": lambda self: self.expression(
 823            exp.BackupProperty, this=self._parse_var(any_token=True)
 824        ),
 825        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
 826        "CHARSET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 827        "CHARACTER SET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 828        "CHECKSUM": lambda self: self._parse_checksum(),
 829        "CLUSTER BY": lambda self: self._parse_cluster(),
 830        "CLUSTERED": lambda self: self._parse_clustered_by(),
 831        "COLLATE": lambda self, **kwargs: self._parse_property_assignment(
 832            exp.CollateProperty, **kwargs
 833        ),
 834        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
 835        "CONTAINS": lambda self: self._parse_contains_property(),
 836        "COPY": lambda self: self._parse_copy_property(),
 837        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
 838        "DATA_DELETION": lambda self: self._parse_data_deletion_property(),
 839        "DEFINER": lambda self: self._parse_definer(),
 840        "DETERMINISTIC": lambda self: self.expression(
 841            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 842        ),
 843        "DYNAMIC": lambda self: self.expression(exp.DynamicProperty),
 844        "DISTKEY": lambda self: self._parse_distkey(),
 845        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
 846        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
 847        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
 848        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
 849        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
 850        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 851        "FREESPACE": lambda self: self._parse_freespace(),
 852        "GLOBAL": lambda self: self.expression(exp.GlobalProperty),
 853        "HEAP": lambda self: self.expression(exp.HeapProperty),
 854        "ICEBERG": lambda self: self.expression(exp.IcebergProperty),
 855        "IMMUTABLE": lambda self: self.expression(
 856            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 857        ),
 858        "INHERITS": lambda self: self.expression(
 859            exp.InheritsProperty, expressions=self._parse_wrapped_csv(self._parse_table)
 860        ),
 861        "INPUT": lambda self: self.expression(exp.InputModelProperty, this=self._parse_schema()),
 862        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
 863        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
 864        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
 865        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
 866        "LIKE": lambda self: self._parse_create_like(),
 867        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
 868        "LOCK": lambda self: self._parse_locking(),
 869        "LOCKING": lambda self: self._parse_locking(),
 870        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
 871        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
 872        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
 873        "MODIFIES": lambda self: self._parse_modifies_property(),
 874        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
 875        "NO": lambda self: self._parse_no_property(),
 876        "ON": lambda self: self._parse_on_property(),
 877        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
 878        "OUTPUT": lambda self: self.expression(exp.OutputModelProperty, this=self._parse_schema()),
 879        "PARTITION": lambda self: self._parse_partitioned_of(),
 880        "PARTITION BY": lambda self: self._parse_partitioned_by(),
 881        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
 882        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
 883        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
 884        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
 885        "READS": lambda self: self._parse_reads_property(),
 886        "REMOTE": lambda self: self._parse_remote_with_connection(),
 887        "RETURNS": lambda self: self._parse_returns(),
 888        "STRICT": lambda self: self.expression(exp.StrictProperty),
 889        "ROW": lambda self: self._parse_row(),
 890        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
 891        "SAMPLE": lambda self: self.expression(
 892            exp.SampleProperty, this=self._match_text_seq("BY") and self._parse_bitwise()
 893        ),
 894        "SECURE": lambda self: self.expression(exp.SecureProperty),
 895        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
 896        "SETTINGS": lambda self: self.expression(
 897            exp.SettingsProperty, expressions=self._parse_csv(self._parse_set_item)
 898        ),
 899        "SHARING": lambda self: self._parse_property_assignment(exp.SharingProperty),
 900        "SORTKEY": lambda self: self._parse_sortkey(),
 901        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
 902        "STABLE": lambda self: self.expression(
 903            exp.StabilityProperty, this=exp.Literal.string("STABLE")
 904        ),
 905        "STORED": lambda self: self._parse_stored(),
 906        "SYSTEM_VERSIONING": lambda self: self._parse_system_versioning_property(),
 907        "TBLPROPERTIES": lambda self: self._parse_wrapped_properties(),
 908        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
 909        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
 910        "TO": lambda self: self._parse_to_table(),
 911        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
 912        "TRANSFORM": lambda self: self.expression(
 913            exp.TransformModelProperty, expressions=self._parse_wrapped_csv(self._parse_expression)
 914        ),
 915        "TTL": lambda self: self._parse_ttl(),
 916        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 917        "UNLOGGED": lambda self: self.expression(exp.UnloggedProperty),
 918        "VOLATILE": lambda self: self._parse_volatile_property(),
 919        "WITH": lambda self: self._parse_with_property(),
 920    }
 921
 922    CONSTRAINT_PARSERS = {
 923        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
 924        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
 925        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
 926        "CHARACTER SET": lambda self: self.expression(
 927            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
 928        ),
 929        "CHECK": lambda self: self.expression(
 930            exp.CheckColumnConstraint,
 931            this=self._parse_wrapped(self._parse_assignment),
 932            enforced=self._match_text_seq("ENFORCED"),
 933        ),
 934        "COLLATE": lambda self: self.expression(
 935            exp.CollateColumnConstraint,
 936            this=self._parse_identifier() or self._parse_column(),
 937        ),
 938        "COMMENT": lambda self: self.expression(
 939            exp.CommentColumnConstraint, this=self._parse_string()
 940        ),
 941        "COMPRESS": lambda self: self._parse_compress(),
 942        "CLUSTERED": lambda self: self.expression(
 943            exp.ClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
 944        ),
 945        "NONCLUSTERED": lambda self: self.expression(
 946            exp.NonClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
 947        ),
 948        "DEFAULT": lambda self: self.expression(
 949            exp.DefaultColumnConstraint, this=self._parse_bitwise()
 950        ),
 951        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
 952        "EPHEMERAL": lambda self: self.expression(
 953            exp.EphemeralColumnConstraint, this=self._parse_bitwise()
 954        ),
 955        "EXCLUDE": lambda self: self.expression(
 956            exp.ExcludeColumnConstraint, this=self._parse_index_params()
 957        ),
 958        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
 959        "FORMAT": lambda self: self.expression(
 960            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
 961        ),
 962        "GENERATED": lambda self: self._parse_generated_as_identity(),
 963        "IDENTITY": lambda self: self._parse_auto_increment(),
 964        "INLINE": lambda self: self._parse_inline(),
 965        "LIKE": lambda self: self._parse_create_like(),
 966        "NOT": lambda self: self._parse_not_constraint(),
 967        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
 968        "ON": lambda self: (
 969            self._match(TokenType.UPDATE)
 970            and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function())
 971        )
 972        or self.expression(exp.OnProperty, this=self._parse_id_var()),
 973        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
 974        "PERIOD": lambda self: self._parse_period_for_system_time(),
 975        "PRIMARY KEY": lambda self: self._parse_primary_key(),
 976        "REFERENCES": lambda self: self._parse_references(match=False),
 977        "TITLE": lambda self: self.expression(
 978            exp.TitleColumnConstraint, this=self._parse_var_or_string()
 979        ),
 980        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
 981        "UNIQUE": lambda self: self._parse_unique(),
 982        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
 983        "WITH": lambda self: self.expression(
 984            exp.Properties, expressions=self._parse_wrapped_properties()
 985        ),
 986    }
 987
 988    ALTER_PARSERS = {
 989        "ADD": lambda self: self._parse_alter_table_add(),
 990        "ALTER": lambda self: self._parse_alter_table_alter(),
 991        "CLUSTER BY": lambda self: self._parse_cluster(wrapped=True),
 992        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
 993        "DROP": lambda self: self._parse_alter_table_drop(),
 994        "RENAME": lambda self: self._parse_alter_table_rename(),
 995        "SET": lambda self: self._parse_alter_table_set(),
 996    }
 997
 998    ALTER_ALTER_PARSERS = {
 999        "DISTKEY": lambda self: self._parse_alter_diststyle(),
1000        "DISTSTYLE": lambda self: self._parse_alter_diststyle(),
1001        "SORTKEY": lambda self: self._parse_alter_sortkey(),
1002        "COMPOUND": lambda self: self._parse_alter_sortkey(compound=True),
1003    }
1004
1005    SCHEMA_UNNAMED_CONSTRAINTS = {
1006        "CHECK",
1007        "EXCLUDE",
1008        "FOREIGN KEY",
1009        "LIKE",
1010        "PERIOD",
1011        "PRIMARY KEY",
1012        "UNIQUE",
1013    }
1014
1015    NO_PAREN_FUNCTION_PARSERS = {
1016        "ANY": lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
1017        "CASE": lambda self: self._parse_case(),
1018        "CONNECT_BY_ROOT": lambda self: self.expression(
1019            exp.ConnectByRoot, this=self._parse_column()
1020        ),
1021        "IF": lambda self: self._parse_if(),
1022        "NEXT": lambda self: self._parse_next_value_for(),
1023    }
1024
1025    INVALID_FUNC_NAME_TOKENS = {
1026        TokenType.IDENTIFIER,
1027        TokenType.STRING,
1028    }
1029
1030    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
1031
1032    KEY_VALUE_DEFINITIONS = (exp.Alias, exp.EQ, exp.PropertyEQ, exp.Slice)
1033
1034    FUNCTION_PARSERS = {
1035        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
1036        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
1037        "DECODE": lambda self: self._parse_decode(),
1038        "EXTRACT": lambda self: self._parse_extract(),
1039        "GAP_FILL": lambda self: self._parse_gap_fill(),
1040        "JSON_OBJECT": lambda self: self._parse_json_object(),
1041        "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
1042        "JSON_TABLE": lambda self: self._parse_json_table(),
1043        "MATCH": lambda self: self._parse_match_against(),
1044        "OPENJSON": lambda self: self._parse_open_json(),
1045        "POSITION": lambda self: self._parse_position(),
1046        "PREDICT": lambda self: self._parse_predict(),
1047        "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
1048        "STRING_AGG": lambda self: self._parse_string_agg(),
1049        "SUBSTRING": lambda self: self._parse_substring(),
1050        "TRIM": lambda self: self._parse_trim(),
1051        "TRY_CAST": lambda self: self._parse_cast(False, safe=True),
1052        "TRY_CONVERT": lambda self: self._parse_convert(False, safe=True),
1053    }
1054
1055    QUERY_MODIFIER_PARSERS = {
1056        TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
1057        TokenType.PREWHERE: lambda self: ("prewhere", self._parse_prewhere()),
1058        TokenType.WHERE: lambda self: ("where", self._parse_where()),
1059        TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
1060        TokenType.HAVING: lambda self: ("having", self._parse_having()),
1061        TokenType.QUALIFY: lambda self: ("qualify", self._parse_qualify()),
1062        TokenType.WINDOW: lambda self: ("windows", self._parse_window_clause()),
1063        TokenType.ORDER_BY: lambda self: ("order", self._parse_order()),
1064        TokenType.LIMIT: lambda self: ("limit", self._parse_limit()),
1065        TokenType.FETCH: lambda self: ("limit", self._parse_limit()),
1066        TokenType.OFFSET: lambda self: ("offset", self._parse_offset()),
1067        TokenType.FOR: lambda self: ("locks", self._parse_locks()),
1068        TokenType.LOCK: lambda self: ("locks", self._parse_locks()),
1069        TokenType.TABLE_SAMPLE: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
1070        TokenType.USING: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
1071        TokenType.CLUSTER_BY: lambda self: (
1072            "cluster",
1073            self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
1074        ),
1075        TokenType.DISTRIBUTE_BY: lambda self: (
1076            "distribute",
1077            self._parse_sort(exp.Distribute, TokenType.DISTRIBUTE_BY),
1078        ),
1079        TokenType.SORT_BY: lambda self: ("sort", self._parse_sort(exp.Sort, TokenType.SORT_BY)),
1080        TokenType.CONNECT_BY: lambda self: ("connect", self._parse_connect(skip_start_token=True)),
1081        TokenType.START_WITH: lambda self: ("connect", self._parse_connect()),
1082    }
1083
1084    SET_PARSERS = {
1085        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
1086        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
1087        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
1088        "TRANSACTION": lambda self: self._parse_set_transaction(),
1089    }
1090
1091    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
1092
1093    TYPE_LITERAL_PARSERS = {
1094        exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
1095    }
1096
1097    TYPE_CONVERTERS: t.Dict[exp.DataType.Type, t.Callable[[exp.DataType], exp.DataType]] = {}
1098
1099    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
1100
1101    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
1102
1103    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
1104    TRANSACTION_CHARACTERISTICS: OPTIONS_TYPE = {
1105        "ISOLATION": (
1106            ("LEVEL", "REPEATABLE", "READ"),
1107            ("LEVEL", "READ", "COMMITTED"),
1108            ("LEVEL", "READ", "UNCOMITTED"),
1109            ("LEVEL", "SERIALIZABLE"),
1110        ),
1111        "READ": ("WRITE", "ONLY"),
1112    }
1113
1114    CONFLICT_ACTIONS: OPTIONS_TYPE = dict.fromkeys(
1115        ("ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK", "UPDATE"), tuple()
1116    )
1117    CONFLICT_ACTIONS["DO"] = ("NOTHING", "UPDATE")
1118
1119    CREATE_SEQUENCE: OPTIONS_TYPE = {
1120        "SCALE": ("EXTEND", "NOEXTEND"),
1121        "SHARD": ("EXTEND", "NOEXTEND"),
1122        "NO": ("CYCLE", "CACHE", "MAXVALUE", "MINVALUE"),
1123        **dict.fromkeys(
1124            (
1125                "SESSION",
1126                "GLOBAL",
1127                "KEEP",
1128                "NOKEEP",
1129                "ORDER",
1130                "NOORDER",
1131                "NOCACHE",
1132                "CYCLE",
1133                "NOCYCLE",
1134                "NOMINVALUE",
1135                "NOMAXVALUE",
1136                "NOSCALE",
1137                "NOSHARD",
1138            ),
1139            tuple(),
1140        ),
1141    }
1142
1143    ISOLATED_LOADING_OPTIONS: OPTIONS_TYPE = {"FOR": ("ALL", "INSERT", "NONE")}
1144
1145    USABLES: OPTIONS_TYPE = dict.fromkeys(
1146        ("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA", "CATALOG"), tuple()
1147    )
1148
1149    CAST_ACTIONS: OPTIONS_TYPE = dict.fromkeys(("RENAME", "ADD"), ("FIELDS",))
1150
1151    SCHEMA_BINDING_OPTIONS: OPTIONS_TYPE = {
1152        "TYPE": ("EVOLUTION",),
1153        **dict.fromkeys(("BINDING", "COMPENSATION", "EVOLUTION"), tuple()),
1154    }
1155
1156    KEY_CONSTRAINT_OPTIONS: OPTIONS_TYPE = {
1157        "NOT": ("ENFORCED",),
1158        "MATCH": (
1159            "FULL",
1160            "PARTIAL",
1161            "SIMPLE",
1162        ),
1163        "INITIALLY": ("DEFERRED", "IMMEDIATE"),
1164        **dict.fromkeys(("DEFERRABLE", "NORELY"), tuple()),
1165    }
1166
1167    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
1168
1169    CLONE_KEYWORDS = {"CLONE", "COPY"}
1170    HISTORICAL_DATA_PREFIX = {"AT", "BEFORE", "END"}
1171    HISTORICAL_DATA_KIND = {"TIMESTAMP", "OFFSET", "STATEMENT", "STREAM"}
1172
1173    OPCLASS_FOLLOW_KEYWORDS = {"ASC", "DESC", "NULLS", "WITH"}
1174
1175    OPTYPE_FOLLOW_TOKENS = {TokenType.COMMA, TokenType.R_PAREN}
1176
1177    TABLE_INDEX_HINT_TOKENS = {TokenType.FORCE, TokenType.IGNORE, TokenType.USE}
1178
1179    VIEW_ATTRIBUTES = {"ENCRYPTION", "SCHEMABINDING", "VIEW_METADATA"}
1180
1181    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
1182    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
1183    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
1184
1185    JSON_KEY_VALUE_SEPARATOR_TOKENS = {TokenType.COLON, TokenType.COMMA, TokenType.IS}
1186
1187    FETCH_TOKENS = ID_VAR_TOKENS - {TokenType.ROW, TokenType.ROWS, TokenType.PERCENT}
1188
1189    ADD_CONSTRAINT_TOKENS = {
1190        TokenType.CONSTRAINT,
1191        TokenType.FOREIGN_KEY,
1192        TokenType.INDEX,
1193        TokenType.KEY,
1194        TokenType.PRIMARY_KEY,
1195        TokenType.UNIQUE,
1196    }
1197
1198    DISTINCT_TOKENS = {TokenType.DISTINCT}
1199
1200    NULL_TOKENS = {TokenType.NULL}
1201
1202    UNNEST_OFFSET_ALIAS_TOKENS = ID_VAR_TOKENS - SET_OPERATIONS
1203
1204    SELECT_START_TOKENS = {TokenType.L_PAREN, TokenType.WITH, TokenType.SELECT}
1205
1206    COPY_INTO_VARLEN_OPTIONS = {"FILE_FORMAT", "COPY_OPTIONS", "FORMAT_OPTIONS", "CREDENTIAL"}
1207
1208    STRICT_CAST = True
1209
1210    PREFIXED_PIVOT_COLUMNS = False
1211    IDENTIFY_PIVOT_STRINGS = False
1212
1213    LOG_DEFAULTS_TO_LN = False
1214
1215    # Whether ADD is present for each column added by ALTER TABLE
1216    ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
1217
1218    # Whether the table sample clause expects CSV syntax
1219    TABLESAMPLE_CSV = False
1220
1221    # The default method used for table sampling
1222    DEFAULT_SAMPLING_METHOD: t.Optional[str] = None
1223
1224    # Whether the SET command needs a delimiter (e.g. "=") for assignments
1225    SET_REQUIRES_ASSIGNMENT_DELIMITER = True
1226
1227    # Whether the TRIM function expects the characters to trim as its first argument
1228    TRIM_PATTERN_FIRST = False
1229
1230    # Whether string aliases are supported `SELECT COUNT(*) 'count'`
1231    STRING_ALIASES = False
1232
1233    # Whether query modifiers such as LIMIT are attached to the UNION node (vs its right operand)
1234    MODIFIERS_ATTACHED_TO_SET_OP = True
1235    SET_OP_MODIFIERS = {"order", "limit", "offset"}
1236
1237    # Whether to parse IF statements that aren't followed by a left parenthesis as commands
1238    NO_PAREN_IF_COMMANDS = True
1239
1240    # Whether the -> and ->> operators expect documents of type JSON (e.g. Postgres)
1241    JSON_ARROWS_REQUIRE_JSON_TYPE = False
1242
1243    # Whether the `:` operator is used to extract a value from a VARIANT column
1244    COLON_IS_VARIANT_EXTRACT = False
1245
1246    # Whether or not a VALUES keyword needs to be followed by '(' to form a VALUES clause.
1247    # If this is True and '(' is not found, the keyword will be treated as an identifier
1248    VALUES_FOLLOWED_BY_PAREN = True
1249
1250    # Whether implicit unnesting is supported, e.g. SELECT 1 FROM y.z AS z, z.a (Redshift)
1251    SUPPORTS_IMPLICIT_UNNEST = False
1252
1253    # Whether or not interval spans are supported, INTERVAL 1 YEAR TO MONTHS
1254    INTERVAL_SPANS = True
1255
1256    # Whether a PARTITION clause can follow a table reference
1257    SUPPORTS_PARTITION_SELECTION = False
1258
1259    __slots__ = (
1260        "error_level",
1261        "error_message_context",
1262        "max_errors",
1263        "dialect",
1264        "sql",
1265        "errors",
1266        "_tokens",
1267        "_index",
1268        "_curr",
1269        "_next",
1270        "_prev",
1271        "_prev_comments",
1272    )
1273
1274    # Autofilled
1275    SHOW_TRIE: t.Dict = {}
1276    SET_TRIE: t.Dict = {}
1277
1278    def __init__(
1279        self,
1280        error_level: t.Optional[ErrorLevel] = None,
1281        error_message_context: int = 100,
1282        max_errors: int = 3,
1283        dialect: DialectType = None,
1284    ):
1285        from sqlglot.dialects import Dialect
1286
1287        self.error_level = error_level or ErrorLevel.IMMEDIATE
1288        self.error_message_context = error_message_context
1289        self.max_errors = max_errors
1290        self.dialect = Dialect.get_or_raise(dialect)
1291        self.reset()
1292
1293    def reset(self):
1294        self.sql = ""
1295        self.errors = []
1296        self._tokens = []
1297        self._index = 0
1298        self._curr = None
1299        self._next = None
1300        self._prev = None
1301        self._prev_comments = None
1302
1303    def parse(
1304        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1305    ) -> t.List[t.Optional[exp.Expression]]:
1306        """
1307        Parses a list of tokens and returns a list of syntax trees, one tree
1308        per parsed SQL statement.
1309
1310        Args:
1311            raw_tokens: The list of tokens.
1312            sql: The original SQL string, used to produce helpful debug messages.
1313
1314        Returns:
1315            The list of the produced syntax trees.
1316        """
1317        return self._parse(
1318            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1319        )
1320
1321    def parse_into(
1322        self,
1323        expression_types: exp.IntoType,
1324        raw_tokens: t.List[Token],
1325        sql: t.Optional[str] = None,
1326    ) -> t.List[t.Optional[exp.Expression]]:
1327        """
1328        Parses a list of tokens into a given Expression type. If a collection of Expression
1329        types is given instead, this method will try to parse the token list into each one
1330        of them, stopping at the first for which the parsing succeeds.
1331
1332        Args:
1333            expression_types: The expression type(s) to try and parse the token list into.
1334            raw_tokens: The list of tokens.
1335            sql: The original SQL string, used to produce helpful debug messages.
1336
1337        Returns:
1338            The target Expression.
1339        """
1340        errors = []
1341        for expression_type in ensure_list(expression_types):
1342            parser = self.EXPRESSION_PARSERS.get(expression_type)
1343            if not parser:
1344                raise TypeError(f"No parser registered for {expression_type}")
1345
1346            try:
1347                return self._parse(parser, raw_tokens, sql)
1348            except ParseError as e:
1349                e.errors[0]["into_expression"] = expression_type
1350                errors.append(e)
1351
1352        raise ParseError(
1353            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1354            errors=merge_errors(errors),
1355        ) from errors[-1]
1356
1357    def _parse(
1358        self,
1359        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
1360        raw_tokens: t.List[Token],
1361        sql: t.Optional[str] = None,
1362    ) -> t.List[t.Optional[exp.Expression]]:
1363        self.reset()
1364        self.sql = sql or ""
1365
1366        total = len(raw_tokens)
1367        chunks: t.List[t.List[Token]] = [[]]
1368
1369        for i, token in enumerate(raw_tokens):
1370            if token.token_type == TokenType.SEMICOLON:
1371                if token.comments:
1372                    chunks.append([token])
1373
1374                if i < total - 1:
1375                    chunks.append([])
1376            else:
1377                chunks[-1].append(token)
1378
1379        expressions = []
1380
1381        for tokens in chunks:
1382            self._index = -1
1383            self._tokens = tokens
1384            self._advance()
1385
1386            expressions.append(parse_method(self))
1387
1388            if self._index < len(self._tokens):
1389                self.raise_error("Invalid expression / Unexpected token")
1390
1391            self.check_errors()
1392
1393        return expressions
1394
1395    def check_errors(self) -> None:
1396        """Logs or raises any found errors, depending on the chosen error level setting."""
1397        if self.error_level == ErrorLevel.WARN:
1398            for error in self.errors:
1399                logger.error(str(error))
1400        elif self.error_level == ErrorLevel.RAISE and self.errors:
1401            raise ParseError(
1402                concat_messages(self.errors, self.max_errors),
1403                errors=merge_errors(self.errors),
1404            )
1405
1406    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1407        """
1408        Appends an error in the list of recorded errors or raises it, depending on the chosen
1409        error level setting.
1410        """
1411        token = token or self._curr or self._prev or Token.string("")
1412        start = token.start
1413        end = token.end + 1
1414        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1415        highlight = self.sql[start:end]
1416        end_context = self.sql[end : end + self.error_message_context]
1417
1418        error = ParseError.new(
1419            f"{message}. Line {token.line}, Col: {token.col}.\n"
1420            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1421            description=message,
1422            line=token.line,
1423            col=token.col,
1424            start_context=start_context,
1425            highlight=highlight,
1426            end_context=end_context,
1427        )
1428
1429        if self.error_level == ErrorLevel.IMMEDIATE:
1430            raise error
1431
1432        self.errors.append(error)
1433
1434    def expression(
1435        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1436    ) -> E:
1437        """
1438        Creates a new, validated Expression.
1439
1440        Args:
1441            exp_class: The expression class to instantiate.
1442            comments: An optional list of comments to attach to the expression.
1443            kwargs: The arguments to set for the expression along with their respective values.
1444
1445        Returns:
1446            The target expression.
1447        """
1448        instance = exp_class(**kwargs)
1449        instance.add_comments(comments) if comments else self._add_comments(instance)
1450        return self.validate_expression(instance)
1451
1452    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
1453        if expression and self._prev_comments:
1454            expression.add_comments(self._prev_comments)
1455            self._prev_comments = None
1456
1457    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1458        """
1459        Validates an Expression, making sure that all its mandatory arguments are set.
1460
1461        Args:
1462            expression: The expression to validate.
1463            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1464
1465        Returns:
1466            The validated expression.
1467        """
1468        if self.error_level != ErrorLevel.IGNORE:
1469            for error_message in expression.error_messages(args):
1470                self.raise_error(error_message)
1471
1472        return expression
1473
1474    def _find_sql(self, start: Token, end: Token) -> str:
1475        return self.sql[start.start : end.end + 1]
1476
1477    def _is_connected(self) -> bool:
1478        return self._prev and self._curr and self._prev.end + 1 == self._curr.start
1479
1480    def _advance(self, times: int = 1) -> None:
1481        self._index += times
1482        self._curr = seq_get(self._tokens, self._index)
1483        self._next = seq_get(self._tokens, self._index + 1)
1484
1485        if self._index > 0:
1486            self._prev = self._tokens[self._index - 1]
1487            self._prev_comments = self._prev.comments
1488        else:
1489            self._prev = None
1490            self._prev_comments = None
1491
1492    def _retreat(self, index: int) -> None:
1493        if index != self._index:
1494            self._advance(index - self._index)
1495
1496    def _warn_unsupported(self) -> None:
1497        if len(self._tokens) <= 1:
1498            return
1499
1500        # We use _find_sql because self.sql may comprise multiple chunks, and we're only
1501        # interested in emitting a warning for the one being currently processed.
1502        sql = self._find_sql(self._tokens[0], self._tokens[-1])[: self.error_message_context]
1503
1504        logger.warning(
1505            f"'{sql}' contains unsupported syntax. Falling back to parsing as a 'Command'."
1506        )
1507
1508    def _parse_command(self) -> exp.Command:
1509        self._warn_unsupported()
1510        return self.expression(
1511            exp.Command,
1512            comments=self._prev_comments,
1513            this=self._prev.text.upper(),
1514            expression=self._parse_string(),
1515        )
1516
1517    def _try_parse(self, parse_method: t.Callable[[], T], retreat: bool = False) -> t.Optional[T]:
1518        """
1519        Attemps to backtrack if a parse function that contains a try/catch internally raises an error.
1520        This behavior can be different depending on the uset-set ErrorLevel, so _try_parse aims to
1521        solve this by setting & resetting the parser state accordingly
1522        """
1523        index = self._index
1524        error_level = self.error_level
1525
1526        self.error_level = ErrorLevel.IMMEDIATE
1527        try:
1528            this = parse_method()
1529        except ParseError:
1530            this = None
1531        finally:
1532            if not this or retreat:
1533                self._retreat(index)
1534            self.error_level = error_level
1535
1536        return this
1537
1538    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
1539        start = self._prev
1540        exists = self._parse_exists() if allow_exists else None
1541
1542        self._match(TokenType.ON)
1543
1544        materialized = self._match_text_seq("MATERIALIZED")
1545        kind = self._match_set(self.CREATABLES) and self._prev
1546        if not kind:
1547            return self._parse_as_command(start)
1548
1549        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1550            this = self._parse_user_defined_function(kind=kind.token_type)
1551        elif kind.token_type == TokenType.TABLE:
1552            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
1553        elif kind.token_type == TokenType.COLUMN:
1554            this = self._parse_column()
1555        else:
1556            this = self._parse_id_var()
1557
1558        self._match(TokenType.IS)
1559
1560        return self.expression(
1561            exp.Comment,
1562            this=this,
1563            kind=kind.text,
1564            expression=self._parse_string(),
1565            exists=exists,
1566            materialized=materialized,
1567        )
1568
1569    def _parse_to_table(
1570        self,
1571    ) -> exp.ToTableProperty:
1572        table = self._parse_table_parts(schema=True)
1573        return self.expression(exp.ToTableProperty, this=table)
1574
1575    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
1576    def _parse_ttl(self) -> exp.Expression:
1577        def _parse_ttl_action() -> t.Optional[exp.Expression]:
1578            this = self._parse_bitwise()
1579
1580            if self._match_text_seq("DELETE"):
1581                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
1582            if self._match_text_seq("RECOMPRESS"):
1583                return self.expression(
1584                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
1585                )
1586            if self._match_text_seq("TO", "DISK"):
1587                return self.expression(
1588                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
1589                )
1590            if self._match_text_seq("TO", "VOLUME"):
1591                return self.expression(
1592                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
1593                )
1594
1595            return this
1596
1597        expressions = self._parse_csv(_parse_ttl_action)
1598        where = self._parse_where()
1599        group = self._parse_group()
1600
1601        aggregates = None
1602        if group and self._match(TokenType.SET):
1603            aggregates = self._parse_csv(self._parse_set_item)
1604
1605        return self.expression(
1606            exp.MergeTreeTTL,
1607            expressions=expressions,
1608            where=where,
1609            group=group,
1610            aggregates=aggregates,
1611        )
1612
1613    def _parse_statement(self) -> t.Optional[exp.Expression]:
1614        if self._curr is None:
1615            return None
1616
1617        if self._match_set(self.STATEMENT_PARSERS):
1618            return self.STATEMENT_PARSERS[self._prev.token_type](self)
1619
1620        if self._match_set(self.dialect.tokenizer.COMMANDS):
1621            return self._parse_command()
1622
1623        expression = self._parse_expression()
1624        expression = self._parse_set_operations(expression) if expression else self._parse_select()
1625        return self._parse_query_modifiers(expression)
1626
1627    def _parse_drop(self, exists: bool = False) -> exp.Drop | exp.Command:
1628        start = self._prev
1629        temporary = self._match(TokenType.TEMPORARY)
1630        materialized = self._match_text_seq("MATERIALIZED")
1631
1632        kind = self._match_set(self.CREATABLES) and self._prev.text
1633        if not kind:
1634            return self._parse_as_command(start)
1635
1636        if_exists = exists or self._parse_exists()
1637        table = self._parse_table_parts(
1638            schema=True, is_db_reference=self._prev.token_type == TokenType.SCHEMA
1639        )
1640
1641        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
1642
1643        if self._match(TokenType.L_PAREN, advance=False):
1644            expressions = self._parse_wrapped_csv(self._parse_types)
1645        else:
1646            expressions = None
1647
1648        return self.expression(
1649            exp.Drop,
1650            comments=start.comments,
1651            exists=if_exists,
1652            this=table,
1653            expressions=expressions,
1654            kind=kind.upper(),
1655            temporary=temporary,
1656            materialized=materialized,
1657            cascade=self._match_text_seq("CASCADE"),
1658            constraints=self._match_text_seq("CONSTRAINTS"),
1659            purge=self._match_text_seq("PURGE"),
1660            cluster=cluster,
1661        )
1662
1663    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
1664        return (
1665            self._match_text_seq("IF")
1666            and (not not_ or self._match(TokenType.NOT))
1667            and self._match(TokenType.EXISTS)
1668        )
1669
1670    def _parse_create(self) -> exp.Create | exp.Command:
1671        # Note: this can't be None because we've matched a statement parser
1672        start = self._prev
1673        comments = self._prev_comments
1674
1675        replace = (
1676            start.token_type == TokenType.REPLACE
1677            or self._match_pair(TokenType.OR, TokenType.REPLACE)
1678            or self._match_pair(TokenType.OR, TokenType.ALTER)
1679        )
1680
1681        unique = self._match(TokenType.UNIQUE)
1682
1683        if self._match_text_seq("CLUSTERED", "COLUMNSTORE"):
1684            clustered = True
1685        elif self._match_text_seq("NONCLUSTERED", "COLUMNSTORE") or self._match_text_seq(
1686            "COLUMNSTORE"
1687        ):
1688            clustered = False
1689        else:
1690            clustered = None
1691
1692        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
1693            self._advance()
1694
1695        properties = None
1696        create_token = self._match_set(self.CREATABLES) and self._prev
1697
1698        if not create_token:
1699            # exp.Properties.Location.POST_CREATE
1700            properties = self._parse_properties()
1701            create_token = self._match_set(self.CREATABLES) and self._prev
1702
1703            if not properties or not create_token:
1704                return self._parse_as_command(start)
1705
1706        concurrently = self._match_text_seq("CONCURRENTLY")
1707        exists = self._parse_exists(not_=True)
1708        this = None
1709        expression: t.Optional[exp.Expression] = None
1710        indexes = None
1711        no_schema_binding = None
1712        begin = None
1713        end = None
1714        clone = None
1715
1716        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
1717            nonlocal properties
1718            if properties and temp_props:
1719                properties.expressions.extend(temp_props.expressions)
1720            elif temp_props:
1721                properties = temp_props
1722
1723        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1724            this = self._parse_user_defined_function(kind=create_token.token_type)
1725
1726            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
1727            extend_props(self._parse_properties())
1728
1729            expression = self._match(TokenType.ALIAS) and self._parse_heredoc()
1730            extend_props(self._parse_properties())
1731
1732            if not expression:
1733                if self._match(TokenType.COMMAND):
1734                    expression = self._parse_as_command(self._prev)
1735                else:
1736                    begin = self._match(TokenType.BEGIN)
1737                    return_ = self._match_text_seq("RETURN")
1738
1739                    if self._match(TokenType.STRING, advance=False):
1740                        # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
1741                        # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
1742                        expression = self._parse_string()
1743                        extend_props(self._parse_properties())
1744                    else:
1745                        expression = self._parse_statement()
1746
1747                    end = self._match_text_seq("END")
1748
1749                    if return_:
1750                        expression = self.expression(exp.Return, this=expression)
1751        elif create_token.token_type == TokenType.INDEX:
1752            # Postgres allows anonymous indexes, eg. CREATE INDEX IF NOT EXISTS ON t(c)
1753            if not self._match(TokenType.ON):
1754                index = self._parse_id_var()
1755                anonymous = False
1756            else:
1757                index = None
1758                anonymous = True
1759
1760            this = self._parse_index(index=index, anonymous=anonymous)
1761        elif create_token.token_type in self.DB_CREATABLES:
1762            table_parts = self._parse_table_parts(
1763                schema=True, is_db_reference=create_token.token_type == TokenType.SCHEMA
1764            )
1765
1766            # exp.Properties.Location.POST_NAME
1767            self._match(TokenType.COMMA)
1768            extend_props(self._parse_properties(before=True))
1769
1770            this = self._parse_schema(this=table_parts)
1771
1772            # exp.Properties.Location.POST_SCHEMA and POST_WITH
1773            extend_props(self._parse_properties())
1774
1775            self._match(TokenType.ALIAS)
1776            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
1777                # exp.Properties.Location.POST_ALIAS
1778                extend_props(self._parse_properties())
1779
1780            if create_token.token_type == TokenType.SEQUENCE:
1781                expression = self._parse_types()
1782                extend_props(self._parse_properties())
1783            else:
1784                expression = self._parse_ddl_select()
1785
1786            if create_token.token_type == TokenType.TABLE:
1787                # exp.Properties.Location.POST_EXPRESSION
1788                extend_props(self._parse_properties())
1789
1790                indexes = []
1791                while True:
1792                    index = self._parse_index()
1793
1794                    # exp.Properties.Location.POST_INDEX
1795                    extend_props(self._parse_properties())
1796
1797                    if not index:
1798                        break
1799                    else:
1800                        self._match(TokenType.COMMA)
1801                        indexes.append(index)
1802            elif create_token.token_type == TokenType.VIEW:
1803                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
1804                    no_schema_binding = True
1805
1806            shallow = self._match_text_seq("SHALLOW")
1807
1808            if self._match_texts(self.CLONE_KEYWORDS):
1809                copy = self._prev.text.lower() == "copy"
1810                clone = self.expression(
1811                    exp.Clone, this=self._parse_table(schema=True), shallow=shallow, copy=copy
1812                )
1813
1814        if self._curr and not self._match_set((TokenType.R_PAREN, TokenType.COMMA), advance=False):
1815            return self._parse_as_command(start)
1816
1817        return self.expression(
1818            exp.Create,
1819            comments=comments,
1820            this=this,
1821            kind=create_token.text.upper(),
1822            replace=replace,
1823            unique=unique,
1824            expression=expression,
1825            exists=exists,
1826            properties=properties,
1827            indexes=indexes,
1828            no_schema_binding=no_schema_binding,
1829            begin=begin,
1830            end=end,
1831            clone=clone,
1832            concurrently=concurrently,
1833            clustered=clustered,
1834        )
1835
1836    def _parse_sequence_properties(self) -> t.Optional[exp.SequenceProperties]:
1837        seq = exp.SequenceProperties()
1838
1839        options = []
1840        index = self._index
1841
1842        while self._curr:
1843            self._match(TokenType.COMMA)
1844            if self._match_text_seq("INCREMENT"):
1845                self._match_text_seq("BY")
1846                self._match_text_seq("=")
1847                seq.set("increment", self._parse_term())
1848            elif self._match_text_seq("MINVALUE"):
1849                seq.set("minvalue", self._parse_term())
1850            elif self._match_text_seq("MAXVALUE"):
1851                seq.set("maxvalue", self._parse_term())
1852            elif self._match(TokenType.START_WITH) or self._match_text_seq("START"):
1853                self._match_text_seq("=")
1854                seq.set("start", self._parse_term())
1855            elif self._match_text_seq("CACHE"):
1856                # T-SQL allows empty CACHE which is initialized dynamically
1857                seq.set("cache", self._parse_number() or True)
1858            elif self._match_text_seq("OWNED", "BY"):
1859                # "OWNED BY NONE" is the default
1860                seq.set("owned", None if self._match_text_seq("NONE") else self._parse_column())
1861            else:
1862                opt = self._parse_var_from_options(self.CREATE_SEQUENCE, raise_unmatched=False)
1863                if opt:
1864                    options.append(opt)
1865                else:
1866                    break
1867
1868        seq.set("options", options if options else None)
1869        return None if self._index == index else seq
1870
1871    def _parse_property_before(self) -> t.Optional[exp.Expression]:
1872        # only used for teradata currently
1873        self._match(TokenType.COMMA)
1874
1875        kwargs = {
1876            "no": self._match_text_seq("NO"),
1877            "dual": self._match_text_seq("DUAL"),
1878            "before": self._match_text_seq("BEFORE"),
1879            "default": self._match_text_seq("DEFAULT"),
1880            "local": (self._match_text_seq("LOCAL") and "LOCAL")
1881            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
1882            "after": self._match_text_seq("AFTER"),
1883            "minimum": self._match_texts(("MIN", "MINIMUM")),
1884            "maximum": self._match_texts(("MAX", "MAXIMUM")),
1885        }
1886
1887        if self._match_texts(self.PROPERTY_PARSERS):
1888            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
1889            try:
1890                return parser(self, **{k: v for k, v in kwargs.items() if v})
1891            except TypeError:
1892                self.raise_error(f"Cannot parse property '{self._prev.text}'")
1893
1894        return None
1895
1896    def _parse_wrapped_properties(self) -> t.List[exp.Expression]:
1897        return self._parse_wrapped_csv(self._parse_property)
1898
1899    def _parse_property(self) -> t.Optional[exp.Expression]:
1900        if self._match_texts(self.PROPERTY_PARSERS):
1901            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
1902
1903        if self._match(TokenType.DEFAULT) and self._match_texts(self.PROPERTY_PARSERS):
1904            return self.PROPERTY_PARSERS[self._prev.text.upper()](self, default=True)
1905
1906        if self._match_text_seq("COMPOUND", "SORTKEY"):
1907            return self._parse_sortkey(compound=True)
1908
1909        if self._match_text_seq("SQL", "SECURITY"):
1910            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
1911
1912        index = self._index
1913        key = self._parse_column()
1914
1915        if not self._match(TokenType.EQ):
1916            self._retreat(index)
1917            return self._parse_sequence_properties()
1918
1919        # Transform the key to exp.Dot if it's dotted identifiers wrapped in exp.Column or to exp.Var otherwise
1920        if isinstance(key, exp.Column):
1921            key = key.to_dot() if len(key.parts) > 1 else exp.var(key.name)
1922
1923        value = self._parse_bitwise() or self._parse_var(any_token=True)
1924
1925        # Transform the value to exp.Var if it was parsed as exp.Column(exp.Identifier())
1926        if isinstance(value, exp.Column):
1927            value = exp.var(value.name)
1928
1929        return self.expression(exp.Property, this=key, value=value)
1930
1931    def _parse_stored(self) -> exp.FileFormatProperty:
1932        self._match(TokenType.ALIAS)
1933
1934        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
1935        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
1936
1937        return self.expression(
1938            exp.FileFormatProperty,
1939            this=(
1940                self.expression(
1941                    exp.InputOutputFormat, input_format=input_format, output_format=output_format
1942                )
1943                if input_format or output_format
1944                else self._parse_var_or_string() or self._parse_number() or self._parse_id_var()
1945            ),
1946        )
1947
1948    def _parse_unquoted_field(self) -> t.Optional[exp.Expression]:
1949        field = self._parse_field()
1950        if isinstance(field, exp.Identifier) and not field.quoted:
1951            field = exp.var(field)
1952
1953        return field
1954
1955    def _parse_property_assignment(self, exp_class: t.Type[E], **kwargs: t.Any) -> E:
1956        self._match(TokenType.EQ)
1957        self._match(TokenType.ALIAS)
1958
1959        return self.expression(exp_class, this=self._parse_unquoted_field(), **kwargs)
1960
1961    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
1962        properties = []
1963        while True:
1964            if before:
1965                prop = self._parse_property_before()
1966            else:
1967                prop = self._parse_property()
1968            if not prop:
1969                break
1970            for p in ensure_list(prop):
1971                properties.append(p)
1972
1973        if properties:
1974            return self.expression(exp.Properties, expressions=properties)
1975
1976        return None
1977
1978    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
1979        return self.expression(
1980            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
1981        )
1982
1983    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
1984        if self._index >= 2:
1985            pre_volatile_token = self._tokens[self._index - 2]
1986        else:
1987            pre_volatile_token = None
1988
1989        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
1990            return exp.VolatileProperty()
1991
1992        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
1993
1994    def _parse_retention_period(self) -> exp.Var:
1995        # Parse TSQL's HISTORY_RETENTION_PERIOD: {INFINITE | <number> DAY | DAYS | MONTH ...}
1996        number = self._parse_number()
1997        number_str = f"{number} " if number else ""
1998        unit = self._parse_var(any_token=True)
1999        return exp.var(f"{number_str}{unit}")
2000
2001    def _parse_system_versioning_property(
2002        self, with_: bool = False
2003    ) -> exp.WithSystemVersioningProperty:
2004        self._match(TokenType.EQ)
2005        prop = self.expression(
2006            exp.WithSystemVersioningProperty,
2007            **{  # type: ignore
2008                "on": True,
2009                "with": with_,
2010            },
2011        )
2012
2013        if self._match_text_seq("OFF"):
2014            prop.set("on", False)
2015            return prop
2016
2017        self._match(TokenType.ON)
2018        if self._match(TokenType.L_PAREN):
2019            while self._curr and not self._match(TokenType.R_PAREN):
2020                if self._match_text_seq("HISTORY_TABLE", "="):
2021                    prop.set("this", self._parse_table_parts())
2022                elif self._match_text_seq("DATA_CONSISTENCY_CHECK", "="):
2023                    prop.set("data_consistency", self._advance_any() and self._prev.text.upper())
2024                elif self._match_text_seq("HISTORY_RETENTION_PERIOD", "="):
2025                    prop.set("retention_period", self._parse_retention_period())
2026
2027                self._match(TokenType.COMMA)
2028
2029        return prop
2030
2031    def _parse_data_deletion_property(self) -> exp.DataDeletionProperty:
2032        self._match(TokenType.EQ)
2033        on = self._match_text_seq("ON") or not self._match_text_seq("OFF")
2034        prop = self.expression(exp.DataDeletionProperty, on=on)
2035
2036        if self._match(TokenType.L_PAREN):
2037            while self._curr and not self._match(TokenType.R_PAREN):
2038                if self._match_text_seq("FILTER_COLUMN", "="):
2039                    prop.set("filter_column", self._parse_column())
2040                elif self._match_text_seq("RETENTION_PERIOD", "="):
2041                    prop.set("retention_period", self._parse_retention_period())
2042
2043                self._match(TokenType.COMMA)
2044
2045        return prop
2046
2047    def _parse_with_property(self) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
2048        if self._match_text_seq("(", "SYSTEM_VERSIONING"):
2049            prop = self._parse_system_versioning_property(with_=True)
2050            self._match_r_paren()
2051            return prop
2052
2053        if self._match(TokenType.L_PAREN, advance=False):
2054            return self._parse_wrapped_properties()
2055
2056        if self._match_text_seq("JOURNAL"):
2057            return self._parse_withjournaltable()
2058
2059        if self._match_texts(self.VIEW_ATTRIBUTES):
2060            return self.expression(exp.ViewAttributeProperty, this=self._prev.text.upper())
2061
2062        if self._match_text_seq("DATA"):
2063            return self._parse_withdata(no=False)
2064        elif self._match_text_seq("NO", "DATA"):
2065            return self._parse_withdata(no=True)
2066
2067        if self._match(TokenType.SERDE_PROPERTIES, advance=False):
2068            return self._parse_serde_properties(with_=True)
2069
2070        if self._match(TokenType.SCHEMA):
2071            return self.expression(
2072                exp.WithSchemaBindingProperty,
2073                this=self._parse_var_from_options(self.SCHEMA_BINDING_OPTIONS),
2074            )
2075
2076        if not self._next:
2077            return None
2078
2079        return self._parse_withisolatedloading()
2080
2081    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
2082    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
2083        self._match(TokenType.EQ)
2084
2085        user = self._parse_id_var()
2086        self._match(TokenType.PARAMETER)
2087        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
2088
2089        if not user or not host:
2090            return None
2091
2092        return exp.DefinerProperty(this=f"{user}@{host}")
2093
2094    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
2095        self._match(TokenType.TABLE)
2096        self._match(TokenType.EQ)
2097        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
2098
2099    def _parse_log(self, no: bool = False) -> exp.LogProperty:
2100        return self.expression(exp.LogProperty, no=no)
2101
2102    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
2103        return self.expression(exp.JournalProperty, **kwargs)
2104
2105    def _parse_checksum(self) -> exp.ChecksumProperty:
2106        self._match(TokenType.EQ)
2107
2108        on = None
2109        if self._match(TokenType.ON):
2110            on = True
2111        elif self._match_text_seq("OFF"):
2112            on = False
2113
2114        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
2115
2116    def _parse_cluster(self, wrapped: bool = False) -> exp.Cluster:
2117        return self.expression(
2118            exp.Cluster,
2119            expressions=(
2120                self._parse_wrapped_csv(self._parse_ordered)
2121                if wrapped
2122                else self._parse_csv(self._parse_ordered)
2123            ),
2124        )
2125
2126    def _parse_clustered_by(self) -> exp.ClusteredByProperty:
2127        self._match_text_seq("BY")
2128
2129        self._match_l_paren()
2130        expressions = self._parse_csv(self._parse_column)
2131        self._match_r_paren()
2132
2133        if self._match_text_seq("SORTED", "BY"):
2134            self._match_l_paren()
2135            sorted_by = self._parse_csv(self._parse_ordered)
2136            self._match_r_paren()
2137        else:
2138            sorted_by = None
2139
2140        self._match(TokenType.INTO)
2141        buckets = self._parse_number()
2142        self._match_text_seq("BUCKETS")
2143
2144        return self.expression(
2145            exp.ClusteredByProperty,
2146            expressions=expressions,
2147            sorted_by=sorted_by,
2148            buckets=buckets,
2149        )
2150
2151    def _parse_copy_property(self) -> t.Optional[exp.CopyGrantsProperty]:
2152        if not self._match_text_seq("GRANTS"):
2153            self._retreat(self._index - 1)
2154            return None
2155
2156        return self.expression(exp.CopyGrantsProperty)
2157
2158    def _parse_freespace(self) -> exp.FreespaceProperty:
2159        self._match(TokenType.EQ)
2160        return self.expression(
2161            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
2162        )
2163
2164    def _parse_mergeblockratio(
2165        self, no: bool = False, default: bool = False
2166    ) -> exp.MergeBlockRatioProperty:
2167        if self._match(TokenType.EQ):
2168            return self.expression(
2169                exp.MergeBlockRatioProperty,
2170                this=self._parse_number(),
2171                percent=self._match(TokenType.PERCENT),
2172            )
2173
2174        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
2175
2176    def _parse_datablocksize(
2177        self,
2178        default: t.Optional[bool] = None,
2179        minimum: t.Optional[bool] = None,
2180        maximum: t.Optional[bool] = None,
2181    ) -> exp.DataBlocksizeProperty:
2182        self._match(TokenType.EQ)
2183        size = self._parse_number()
2184
2185        units = None
2186        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
2187            units = self._prev.text
2188
2189        return self.expression(
2190            exp.DataBlocksizeProperty,
2191            size=size,
2192            units=units,
2193            default=default,
2194            minimum=minimum,
2195            maximum=maximum,
2196        )
2197
2198    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
2199        self._match(TokenType.EQ)
2200        always = self._match_text_seq("ALWAYS")
2201        manual = self._match_text_seq("MANUAL")
2202        never = self._match_text_seq("NEVER")
2203        default = self._match_text_seq("DEFAULT")
2204
2205        autotemp = None
2206        if self._match_text_seq("AUTOTEMP"):
2207            autotemp = self._parse_schema()
2208
2209        return self.expression(
2210            exp.BlockCompressionProperty,
2211            always=always,
2212            manual=manual,
2213            never=never,
2214            default=default,
2215            autotemp=autotemp,
2216        )
2217
2218    def _parse_withisolatedloading(self) -> t.Optional[exp.IsolatedLoadingProperty]:
2219        index = self._index
2220        no = self._match_text_seq("NO")
2221        concurrent = self._match_text_seq("CONCURRENT")
2222
2223        if not self._match_text_seq("ISOLATED", "LOADING"):
2224            self._retreat(index)
2225            return None
2226
2227        target = self._parse_var_from_options(self.ISOLATED_LOADING_OPTIONS, raise_unmatched=False)
2228        return self.expression(
2229            exp.IsolatedLoadingProperty, no=no, concurrent=concurrent, target=target
2230        )
2231
2232    def _parse_locking(self) -> exp.LockingProperty:
2233        if self._match(TokenType.TABLE):
2234            kind = "TABLE"
2235        elif self._match(TokenType.VIEW):
2236            kind = "VIEW"
2237        elif self._match(TokenType.ROW):
2238            kind = "ROW"
2239        elif self._match_text_seq("DATABASE"):
2240            kind = "DATABASE"
2241        else:
2242            kind = None
2243
2244        if kind in ("DATABASE", "TABLE", "VIEW"):
2245            this = self._parse_table_parts()
2246        else:
2247            this = None
2248
2249        if self._match(TokenType.FOR):
2250            for_or_in = "FOR"
2251        elif self._match(TokenType.IN):
2252            for_or_in = "IN"
2253        else:
2254            for_or_in = None
2255
2256        if self._match_text_seq("ACCESS"):
2257            lock_type = "ACCESS"
2258        elif self._match_texts(("EXCL", "EXCLUSIVE")):
2259            lock_type = "EXCLUSIVE"
2260        elif self._match_text_seq("SHARE"):
2261            lock_type = "SHARE"
2262        elif self._match_text_seq("READ"):
2263            lock_type = "READ"
2264        elif self._match_text_seq("WRITE"):
2265            lock_type = "WRITE"
2266        elif self._match_text_seq("CHECKSUM"):
2267            lock_type = "CHECKSUM"
2268        else:
2269            lock_type = None
2270
2271        override = self._match_text_seq("OVERRIDE")
2272
2273        return self.expression(
2274            exp.LockingProperty,
2275            this=this,
2276            kind=kind,
2277            for_or_in=for_or_in,
2278            lock_type=lock_type,
2279            override=override,
2280        )
2281
2282    def _parse_partition_by(self) -> t.List[exp.Expression]:
2283        if self._match(TokenType.PARTITION_BY):
2284            return self._parse_csv(self._parse_assignment)
2285        return []
2286
2287    def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
2288        def _parse_partition_bound_expr() -> t.Optional[exp.Expression]:
2289            if self._match_text_seq("MINVALUE"):
2290                return exp.var("MINVALUE")
2291            if self._match_text_seq("MAXVALUE"):
2292                return exp.var("MAXVALUE")
2293            return self._parse_bitwise()
2294
2295        this: t.Optional[exp.Expression | t.List[exp.Expression]] = None
2296        expression = None
2297        from_expressions = None
2298        to_expressions = None
2299
2300        if self._match(TokenType.IN):
2301            this = self._parse_wrapped_csv(self._parse_bitwise)
2302        elif self._match(TokenType.FROM):
2303            from_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
2304            self._match_text_seq("TO")
2305            to_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
2306        elif self._match_text_seq("WITH", "(", "MODULUS"):
2307            this = self._parse_number()
2308            self._match_text_seq(",", "REMAINDER")
2309            expression = self._parse_number()
2310            self._match_r_paren()
2311        else:
2312            self.raise_error("Failed to parse partition bound spec.")
2313
2314        return self.expression(
2315            exp.PartitionBoundSpec,
2316            this=this,
2317            expression=expression,
2318            from_expressions=from_expressions,
2319            to_expressions=to_expressions,
2320        )
2321
2322    # https://www.postgresql.org/docs/current/sql-createtable.html
2323    def _parse_partitioned_of(self) -> t.Optional[exp.PartitionedOfProperty]:
2324        if not self._match_text_seq("OF"):
2325            self._retreat(self._index - 1)
2326            return None
2327
2328        this = self._parse_table(schema=True)
2329
2330        if self._match(TokenType.DEFAULT):
2331            expression: exp.Var | exp.PartitionBoundSpec = exp.var("DEFAULT")
2332        elif self._match_text_seq("FOR", "VALUES"):
2333            expression = self._parse_partition_bound_spec()
2334        else:
2335            self.raise_error("Expecting either DEFAULT or FOR VALUES clause.")
2336
2337        return self.expression(exp.PartitionedOfProperty, this=this, expression=expression)
2338
2339    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
2340        self._match(TokenType.EQ)
2341        return self.expression(
2342            exp.PartitionedByProperty,
2343            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
2344        )
2345
2346    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
2347        if self._match_text_seq("AND", "STATISTICS"):
2348            statistics = True
2349        elif self._match_text_seq("AND", "NO", "STATISTICS"):
2350            statistics = False
2351        else:
2352            statistics = None
2353
2354        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
2355
2356    def _parse_contains_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2357        if self._match_text_seq("SQL"):
2358            return self.expression(exp.SqlReadWriteProperty, this="CONTAINS SQL")
2359        return None
2360
2361    def _parse_modifies_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2362        if self._match_text_seq("SQL", "DATA"):
2363            return self.expression(exp.SqlReadWriteProperty, this="MODIFIES SQL DATA")
2364        return None
2365
2366    def _parse_no_property(self) -> t.Optional[exp.Expression]:
2367        if self._match_text_seq("PRIMARY", "INDEX"):
2368            return exp.NoPrimaryIndexProperty()
2369        if self._match_text_seq("SQL"):
2370            return self.expression(exp.SqlReadWriteProperty, this="NO SQL")
2371        return None
2372
2373    def _parse_on_property(self) -> t.Optional[exp.Expression]:
2374        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
2375            return exp.OnCommitProperty()
2376        if self._match_text_seq("COMMIT", "DELETE", "ROWS"):
2377            return exp.OnCommitProperty(delete=True)
2378        return self.expression(exp.OnProperty, this=self._parse_schema(self._parse_id_var()))
2379
2380    def _parse_reads_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
2381        if self._match_text_seq("SQL", "DATA"):
2382            return self.expression(exp.SqlReadWriteProperty, this="READS SQL DATA")
2383        return None
2384
2385    def _parse_distkey(self) -> exp.DistKeyProperty:
2386        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
2387
2388    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
2389        table = self._parse_table(schema=True)
2390
2391        options = []
2392        while self._match_texts(("INCLUDING", "EXCLUDING")):
2393            this = self._prev.text.upper()
2394
2395            id_var = self._parse_id_var()
2396            if not id_var:
2397                return None
2398
2399            options.append(
2400                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
2401            )
2402
2403        return self.expression(exp.LikeProperty, this=table, expressions=options)
2404
2405    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
2406        return self.expression(
2407            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
2408        )
2409
2410    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
2411        self._match(TokenType.EQ)
2412        return self.expression(
2413            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
2414        )
2415
2416    def _parse_remote_with_connection(self) -> exp.RemoteWithConnectionModelProperty:
2417        self._match_text_seq("WITH", "CONNECTION")
2418        return self.expression(
2419            exp.RemoteWithConnectionModelProperty, this=self._parse_table_parts()
2420        )
2421
2422    def _parse_returns(self) -> exp.ReturnsProperty:
2423        value: t.Optional[exp.Expression]
2424        null = None
2425        is_table = self._match(TokenType.TABLE)
2426
2427        if is_table:
2428            if self._match(TokenType.LT):
2429                value = self.expression(
2430                    exp.Schema,
2431                    this="TABLE",
2432                    expressions=self._parse_csv(self._parse_struct_types),
2433                )
2434                if not self._match(TokenType.GT):
2435                    self.raise_error("Expecting >")
2436            else:
2437                value = self._parse_schema(exp.var("TABLE"))
2438        elif self._match_text_seq("NULL", "ON", "NULL", "INPUT"):
2439            null = True
2440            value = None
2441        else:
2442            value = self._parse_types()
2443
2444        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table, null=null)
2445
2446    def _parse_describe(self) -> exp.Describe:
2447        kind = self._match_set(self.CREATABLES) and self._prev.text
2448        style = self._match_texts(("EXTENDED", "FORMATTED", "HISTORY")) and self._prev.text.upper()
2449        if self._match(TokenType.DOT):
2450            style = None
2451            self._retreat(self._index - 2)
2452        this = self._parse_table(schema=True)
2453        properties = self._parse_properties()
2454        expressions = properties.expressions if properties else None
2455        return self.expression(
2456            exp.Describe, this=this, style=style, kind=kind, expressions=expressions
2457        )
2458
2459    def _parse_insert(self) -> exp.Insert:
2460        comments = ensure_list(self._prev_comments)
2461        hint = self._parse_hint()
2462        overwrite = self._match(TokenType.OVERWRITE)
2463        ignore = self._match(TokenType.IGNORE)
2464        local = self._match_text_seq("LOCAL")
2465        alternative = None
2466        is_function = None
2467
2468        if self._match_text_seq("DIRECTORY"):
2469            this: t.Optional[exp.Expression] = self.expression(
2470                exp.Directory,
2471                this=self._parse_var_or_string(),
2472                local=local,
2473                row_format=self._parse_row_format(match_row=True),
2474            )
2475        else:
2476            if self._match(TokenType.OR):
2477                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
2478
2479            self._match(TokenType.INTO)
2480            comments += ensure_list(self._prev_comments)
2481            self._match(TokenType.TABLE)
2482            is_function = self._match(TokenType.FUNCTION)
2483
2484            this = (
2485                self._parse_table(schema=True, parse_partition=True)
2486                if not is_function
2487                else self._parse_function()
2488            )
2489
2490        returning = self._parse_returning()
2491
2492        return self.expression(
2493            exp.Insert,
2494            comments=comments,
2495            hint=hint,
2496            is_function=is_function,
2497            this=this,
2498            stored=self._match_text_seq("STORED") and self._parse_stored(),
2499            by_name=self._match_text_seq("BY", "NAME"),
2500            exists=self._parse_exists(),
2501            where=self._match_pair(TokenType.REPLACE, TokenType.WHERE) and self._parse_assignment(),
2502            expression=self._parse_derived_table_values() or self._parse_ddl_select(),
2503            conflict=self._parse_on_conflict(),
2504            returning=returning or self._parse_returning(),
2505            overwrite=overwrite,
2506            alternative=alternative,
2507            ignore=ignore,
2508        )
2509
2510    def _parse_kill(self) -> exp.Kill:
2511        kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
2512
2513        return self.expression(
2514            exp.Kill,
2515            this=self._parse_primary(),
2516            kind=kind,
2517        )
2518
2519    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
2520        conflict = self._match_text_seq("ON", "CONFLICT")
2521        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
2522
2523        if not conflict and not duplicate:
2524            return None
2525
2526        conflict_keys = None
2527        constraint = None
2528
2529        if conflict:
2530            if self._match_text_seq("ON", "CONSTRAINT"):
2531                constraint = self._parse_id_var()
2532            elif self._match(TokenType.L_PAREN):
2533                conflict_keys = self._parse_csv(self._parse_id_var)
2534                self._match_r_paren()
2535
2536        action = self._parse_var_from_options(self.CONFLICT_ACTIONS)
2537        if self._prev.token_type == TokenType.UPDATE:
2538            self._match(TokenType.SET)
2539            expressions = self._parse_csv(self._parse_equality)
2540        else:
2541            expressions = None
2542
2543        return self.expression(
2544            exp.OnConflict,
2545            duplicate=duplicate,
2546            expressions=expressions,
2547            action=action,
2548            conflict_keys=conflict_keys,
2549            constraint=constraint,
2550        )
2551
2552    def _parse_returning(self) -> t.Optional[exp.Returning]:
2553        if not self._match(TokenType.RETURNING):
2554            return None
2555        return self.expression(
2556            exp.Returning,
2557            expressions=self._parse_csv(self._parse_expression),
2558            into=self._match(TokenType.INTO) and self._parse_table_part(),
2559        )
2560
2561    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2562        if not self._match(TokenType.FORMAT):
2563            return None
2564        return self._parse_row_format()
2565
2566    def _parse_serde_properties(self, with_: bool = False) -> t.Optional[exp.SerdeProperties]:
2567        index = self._index
2568        with_ = with_ or self._match_text_seq("WITH")
2569
2570        if not self._match(TokenType.SERDE_PROPERTIES):
2571            self._retreat(index)
2572            return None
2573        return self.expression(
2574            exp.SerdeProperties,
2575            **{  # type: ignore
2576                "expressions": self._parse_wrapped_properties(),
2577                "with": with_,
2578            },
2579        )
2580
2581    def _parse_row_format(
2582        self, match_row: bool = False
2583    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2584        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
2585            return None
2586
2587        if self._match_text_seq("SERDE"):
2588            this = self._parse_string()
2589
2590            serde_properties = self._parse_serde_properties()
2591
2592            return self.expression(
2593                exp.RowFormatSerdeProperty, this=this, serde_properties=serde_properties
2594            )
2595
2596        self._match_text_seq("DELIMITED")
2597
2598        kwargs = {}
2599
2600        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
2601            kwargs["fields"] = self._parse_string()
2602            if self._match_text_seq("ESCAPED", "BY"):
2603                kwargs["escaped"] = self._parse_string()
2604        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
2605            kwargs["collection_items"] = self._parse_string()
2606        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
2607            kwargs["map_keys"] = self._parse_string()
2608        if self._match_text_seq("LINES", "TERMINATED", "BY"):
2609            kwargs["lines"] = self._parse_string()
2610        if self._match_text_seq("NULL", "DEFINED", "AS"):
2611            kwargs["null"] = self._parse_string()
2612
2613        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
2614
2615    def _parse_load(self) -> exp.LoadData | exp.Command:
2616        if self._match_text_seq("DATA"):
2617            local = self._match_text_seq("LOCAL")
2618            self._match_text_seq("INPATH")
2619            inpath = self._parse_string()
2620            overwrite = self._match(TokenType.OVERWRITE)
2621            self._match_pair(TokenType.INTO, TokenType.TABLE)
2622
2623            return self.expression(
2624                exp.LoadData,
2625                this=self._parse_table(schema=True),
2626                local=local,
2627                overwrite=overwrite,
2628                inpath=inpath,
2629                partition=self._parse_partition(),
2630                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
2631                serde=self._match_text_seq("SERDE") and self._parse_string(),
2632            )
2633        return self._parse_as_command(self._prev)
2634
2635    def _parse_delete(self) -> exp.Delete:
2636        # This handles MySQL's "Multiple-Table Syntax"
2637        # https://dev.mysql.com/doc/refman/8.0/en/delete.html
2638        tables = None
2639        comments = self._prev_comments
2640        if not self._match(TokenType.FROM, advance=False):
2641            tables = self._parse_csv(self._parse_table) or None
2642
2643        returning = self._parse_returning()
2644
2645        return self.expression(
2646            exp.Delete,
2647            comments=comments,
2648            tables=tables,
2649            this=self._match(TokenType.FROM) and self._parse_table(joins=True),
2650            using=self._match(TokenType.USING) and self._parse_table(joins=True),
2651            where=self._parse_where(),
2652            returning=returning or self._parse_returning(),
2653            limit=self._parse_limit(),
2654        )
2655
2656    def _parse_update(self) -> exp.Update:
2657        comments = self._prev_comments
2658        this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
2659        expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
2660        returning = self._parse_returning()
2661        return self.expression(
2662            exp.Update,
2663            comments=comments,
2664            **{  # type: ignore
2665                "this": this,
2666                "expressions": expressions,
2667                "from": self._parse_from(joins=True),
2668                "where": self._parse_where(),
2669                "returning": returning or self._parse_returning(),
2670                "order": self._parse_order(),
2671                "limit": self._parse_limit(),
2672            },
2673        )
2674
2675    def _parse_uncache(self) -> exp.Uncache:
2676        if not self._match(TokenType.TABLE):
2677            self.raise_error("Expecting TABLE after UNCACHE")
2678
2679        return self.expression(
2680            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
2681        )
2682
2683    def _parse_cache(self) -> exp.Cache:
2684        lazy = self._match_text_seq("LAZY")
2685        self._match(TokenType.TABLE)
2686        table = self._parse_table(schema=True)
2687
2688        options = []
2689        if self._match_text_seq("OPTIONS"):
2690            self._match_l_paren()
2691            k = self._parse_string()
2692            self._match(TokenType.EQ)
2693            v = self._parse_string()
2694            options = [k, v]
2695            self._match_r_paren()
2696
2697        self._match(TokenType.ALIAS)
2698        return self.expression(
2699            exp.Cache,
2700            this=table,
2701            lazy=lazy,
2702            options=options,
2703            expression=self._parse_select(nested=True),
2704        )
2705
2706    def _parse_partition(self) -> t.Optional[exp.Partition]:
2707        if not self._match(TokenType.PARTITION):
2708            return None
2709
2710        return self.expression(
2711            exp.Partition, expressions=self._parse_wrapped_csv(self._parse_assignment)
2712        )
2713
2714    def _parse_value(self) -> t.Optional[exp.Tuple]:
2715        if self._match(TokenType.L_PAREN):
2716            expressions = self._parse_csv(self._parse_expression)
2717            self._match_r_paren()
2718            return self.expression(exp.Tuple, expressions=expressions)
2719
2720        # In some dialects we can have VALUES 1, 2 which results in 1 column & 2 rows.
2721        expression = self._parse_expression()
2722        if expression:
2723            return self.expression(exp.Tuple, expressions=[expression])
2724        return None
2725
2726    def _parse_projections(self) -> t.List[exp.Expression]:
2727        return self._parse_expressions()
2728
2729    def _parse_select(
2730        self,
2731        nested: bool = False,
2732        table: bool = False,
2733        parse_subquery_alias: bool = True,
2734        parse_set_operation: bool = True,
2735    ) -> t.Optional[exp.Expression]:
2736        cte = self._parse_with()
2737
2738        if cte:
2739            this = self._parse_statement()
2740
2741            if not this:
2742                self.raise_error("Failed to parse any statement following CTE")
2743                return cte
2744
2745            if "with" in this.arg_types:
2746                this.set("with", cte)
2747            else:
2748                self.raise_error(f"{this.key} does not support CTE")
2749                this = cte
2750
2751            return this
2752
2753        # duckdb supports leading with FROM x
2754        from_ = self._parse_from() if self._match(TokenType.FROM, advance=False) else None
2755
2756        if self._match(TokenType.SELECT):
2757            comments = self._prev_comments
2758
2759            hint = self._parse_hint()
2760
2761            if self._next and not self._next.token_type == TokenType.DOT:
2762                all_ = self._match(TokenType.ALL)
2763                distinct = self._match_set(self.DISTINCT_TOKENS)
2764            else:
2765                all_, distinct = None, None
2766
2767            kind = (
2768                self._match(TokenType.ALIAS)
2769                and self._match_texts(("STRUCT", "VALUE"))
2770                and self._prev.text.upper()
2771            )
2772
2773            if distinct:
2774                distinct = self.expression(
2775                    exp.Distinct,
2776                    on=self._parse_value() if self._match(TokenType.ON) else None,
2777                )
2778
2779            if all_ and distinct:
2780                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
2781
2782            limit = self._parse_limit(top=True)
2783            projections = self._parse_projections()
2784
2785            this = self.expression(
2786                exp.Select,
2787                kind=kind,
2788                hint=hint,
2789                distinct=distinct,
2790                expressions=projections,
2791                limit=limit,
2792            )
2793            this.comments = comments
2794
2795            into = self._parse_into()
2796            if into:
2797                this.set("into", into)
2798
2799            if not from_:
2800                from_ = self._parse_from()
2801
2802            if from_:
2803                this.set("from", from_)
2804
2805            this = self._parse_query_modifiers(this)
2806        elif (table or nested) and self._match(TokenType.L_PAREN):
2807            if self._match(TokenType.PIVOT):
2808                this = self._parse_simplified_pivot()
2809            elif self._match(TokenType.FROM):
2810                this = exp.select("*").from_(
2811                    t.cast(exp.From, self._parse_from(skip_from_token=True))
2812                )
2813            else:
2814                this = (
2815                    self._parse_table()
2816                    if table
2817                    else self._parse_select(nested=True, parse_set_operation=False)
2818                )
2819                this = self._parse_query_modifiers(self._parse_set_operations(this))
2820
2821            self._match_r_paren()
2822
2823            # We return early here so that the UNION isn't attached to the subquery by the
2824            # following call to _parse_set_operations, but instead becomes the parent node
2825            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
2826        elif self._match(TokenType.VALUES, advance=False):
2827            this = self._parse_derived_table_values()
2828        elif from_:
2829            this = exp.select("*").from_(from_.this, copy=False)
2830        elif self._match(TokenType.SUMMARIZE):
2831            table = self._match(TokenType.TABLE)
2832            this = self._parse_select() or self._parse_string() or self._parse_table()
2833            return self.expression(exp.Summarize, this=this, table=table)
2834        else:
2835            this = None
2836
2837        return self._parse_set_operations(this) if parse_set_operation else this
2838
2839    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
2840        if not skip_with_token and not self._match(TokenType.WITH):
2841            return None
2842
2843        comments = self._prev_comments
2844        recursive = self._match(TokenType.RECURSIVE)
2845
2846        expressions = []
2847        while True:
2848            expressions.append(self._parse_cte())
2849
2850            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
2851                break
2852            else:
2853                self._match(TokenType.WITH)
2854
2855        return self.expression(
2856            exp.With, comments=comments, expressions=expressions, recursive=recursive
2857        )
2858
2859    def _parse_cte(self) -> exp.CTE:
2860        alias = self._parse_table_alias(self.ID_VAR_TOKENS)
2861        if not alias or not alias.this:
2862            self.raise_error("Expected CTE to have alias")
2863
2864        self._match(TokenType.ALIAS)
2865        comments = self._prev_comments
2866
2867        if self._match_text_seq("NOT", "MATERIALIZED"):
2868            materialized = False
2869        elif self._match_text_seq("MATERIALIZED"):
2870            materialized = True
2871        else:
2872            materialized = None
2873
2874        return self.expression(
2875            exp.CTE,
2876            this=self._parse_wrapped(self._parse_statement),
2877            alias=alias,
2878            materialized=materialized,
2879            comments=comments,
2880        )
2881
2882    def _parse_table_alias(
2883        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
2884    ) -> t.Optional[exp.TableAlias]:
2885        any_token = self._match(TokenType.ALIAS)
2886        alias = (
2887            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
2888            or self._parse_string_as_identifier()
2889        )
2890
2891        index = self._index
2892        if self._match(TokenType.L_PAREN):
2893            columns = self._parse_csv(self._parse_function_parameter)
2894            self._match_r_paren() if columns else self._retreat(index)
2895        else:
2896            columns = None
2897
2898        if not alias and not columns:
2899            return None
2900
2901        table_alias = self.expression(exp.TableAlias, this=alias, columns=columns)
2902
2903        # We bubble up comments from the Identifier to the TableAlias
2904        if isinstance(alias, exp.Identifier):
2905            table_alias.add_comments(alias.pop_comments())
2906
2907        return table_alias
2908
2909    def _parse_subquery(
2910        self, this: t.Optional[exp.Expression], parse_alias: bool = True
2911    ) -> t.Optional[exp.Subquery]:
2912        if not this:
2913            return None
2914
2915        return self.expression(
2916            exp.Subquery,
2917            this=this,
2918            pivots=self._parse_pivots(),
2919            alias=self._parse_table_alias() if parse_alias else None,
2920        )
2921
2922    def _implicit_unnests_to_explicit(self, this: E) -> E:
2923        from sqlglot.optimizer.normalize_identifiers import normalize_identifiers as _norm
2924
2925        refs = {_norm(this.args["from"].this.copy(), dialect=self.dialect).alias_or_name}
2926        for i, join in enumerate(this.args.get("joins") or []):
2927            table = join.this
2928            normalized_table = table.copy()
2929            normalized_table.meta["maybe_column"] = True
2930            normalized_table = _norm(normalized_table, dialect=self.dialect)
2931
2932            if isinstance(table, exp.Table) and not join.args.get("on"):
2933                if normalized_table.parts[0].name in refs:
2934                    table_as_column = table.to_column()
2935                    unnest = exp.Unnest(expressions=[table_as_column])
2936
2937                    # Table.to_column creates a parent Alias node that we want to convert to
2938                    # a TableAlias and attach to the Unnest, so it matches the parser's output
2939                    if isinstance(table.args.get("alias"), exp.TableAlias):
2940                        table_as_column.replace(table_as_column.this)
2941                        exp.alias_(unnest, None, table=[table.args["alias"].this], copy=False)
2942
2943                    table.replace(unnest)
2944
2945            refs.add(normalized_table.alias_or_name)
2946
2947        return this
2948
2949    def _parse_query_modifiers(
2950        self, this: t.Optional[exp.Expression]
2951    ) -> t.Optional[exp.Expression]:
2952        if isinstance(this, (exp.Query, exp.Table)):
2953            for join in self._parse_joins():
2954                this.append("joins", join)
2955            for lateral in iter(self._parse_lateral, None):
2956                this.append("laterals", lateral)
2957
2958            while True:
2959                if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
2960                    parser = self.QUERY_MODIFIER_PARSERS[self._curr.token_type]
2961                    key, expression = parser(self)
2962
2963                    if expression:
2964                        this.set(key, expression)
2965                        if key == "limit":
2966                            offset = expression.args.pop("offset", None)
2967
2968                            if offset:
2969                                offset = exp.Offset(expression=offset)
2970                                this.set("offset", offset)
2971
2972                                limit_by_expressions = expression.expressions
2973                                expression.set("expressions", None)
2974                                offset.set("expressions", limit_by_expressions)
2975                        continue
2976                break
2977
2978        if self.SUPPORTS_IMPLICIT_UNNEST and this and this.args.get("from"):
2979            this = self._implicit_unnests_to_explicit(this)
2980
2981        return this
2982
2983    def _parse_hint(self) -> t.Optional[exp.Hint]:
2984        if self._match(TokenType.HINT):
2985            hints = []
2986            for hint in iter(
2987                lambda: self._parse_csv(
2988                    lambda: self._parse_function() or self._parse_var(upper=True)
2989                ),
2990                [],
2991            ):
2992                hints.extend(hint)
2993
2994            if not self._match_pair(TokenType.STAR, TokenType.SLASH):
2995                self.raise_error("Expected */ after HINT")
2996
2997            return self.expression(exp.Hint, expressions=hints)
2998
2999        return None
3000
3001    def _parse_into(self) -> t.Optional[exp.Into]:
3002        if not self._match(TokenType.INTO):
3003            return None
3004
3005        temp = self._match(TokenType.TEMPORARY)
3006        unlogged = self._match_text_seq("UNLOGGED")
3007        self._match(TokenType.TABLE)
3008
3009        return self.expression(
3010            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
3011        )
3012
3013    def _parse_from(
3014        self, joins: bool = False, skip_from_token: bool = False
3015    ) -> t.Optional[exp.From]:
3016        if not skip_from_token and not self._match(TokenType.FROM):
3017            return None
3018
3019        return self.expression(
3020            exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
3021        )
3022
3023    def _parse_match_recognize_measure(self) -> exp.MatchRecognizeMeasure:
3024        return self.expression(
3025            exp.MatchRecognizeMeasure,
3026            window_frame=self._match_texts(("FINAL", "RUNNING")) and self._prev.text.upper(),
3027            this=self._parse_expression(),
3028        )
3029
3030    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
3031        if not self._match(TokenType.MATCH_RECOGNIZE):
3032            return None
3033
3034        self._match_l_paren()
3035
3036        partition = self._parse_partition_by()
3037        order = self._parse_order()
3038
3039        measures = (
3040            self._parse_csv(self._parse_match_recognize_measure)
3041            if self._match_text_seq("MEASURES")
3042            else None
3043        )
3044
3045        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
3046            rows = exp.var("ONE ROW PER MATCH")
3047        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
3048            text = "ALL ROWS PER MATCH"
3049            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
3050                text += " SHOW EMPTY MATCHES"
3051            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
3052                text += " OMIT EMPTY MATCHES"
3053            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
3054                text += " WITH UNMATCHED ROWS"
3055            rows = exp.var(text)
3056        else:
3057            rows = None
3058
3059        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
3060            text = "AFTER MATCH SKIP"
3061            if self._match_text_seq("PAST", "LAST", "ROW"):
3062                text += " PAST LAST ROW"
3063            elif self._match_text_seq("TO", "NEXT", "ROW"):
3064                text += " TO NEXT ROW"
3065            elif self._match_text_seq("TO", "FIRST"):
3066                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
3067            elif self._match_text_seq("TO", "LAST"):
3068                text += f" TO LAST {self._advance_any().text}"  # type: ignore
3069            after = exp.var(text)
3070        else:
3071            after = None
3072
3073        if self._match_text_seq("PATTERN"):
3074            self._match_l_paren()
3075
3076            if not self._curr:
3077                self.raise_error("Expecting )", self._curr)
3078
3079            paren = 1
3080            start = self._curr
3081
3082            while self._curr and paren > 0:
3083                if self._curr.token_type == TokenType.L_PAREN:
3084                    paren += 1
3085                if self._curr.token_type == TokenType.R_PAREN:
3086                    paren -= 1
3087
3088                end = self._prev
3089                self._advance()
3090
3091            if paren > 0:
3092                self.raise_error("Expecting )", self._curr)
3093
3094            pattern = exp.var(self._find_sql(start, end))
3095        else:
3096            pattern = None
3097
3098        define = (
3099            self._parse_csv(self._parse_name_as_expression)
3100            if self._match_text_seq("DEFINE")
3101            else None
3102        )
3103
3104        self._match_r_paren()
3105
3106        return self.expression(
3107            exp.MatchRecognize,
3108            partition_by=partition,
3109            order=order,
3110            measures=measures,
3111            rows=rows,
3112            after=after,
3113            pattern=pattern,
3114            define=define,
3115            alias=self._parse_table_alias(),
3116        )
3117
3118    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
3119        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
3120        if not cross_apply and self._match_pair(TokenType.OUTER, TokenType.APPLY):
3121            cross_apply = False
3122
3123        if cross_apply is not None:
3124            this = self._parse_select(table=True)
3125            view = None
3126            outer = None
3127        elif self._match(TokenType.LATERAL):
3128            this = self._parse_select(table=True)
3129            view = self._match(TokenType.VIEW)
3130            outer = self._match(TokenType.OUTER)
3131        else:
3132            return None
3133
3134        if not this:
3135            this = (
3136                self._parse_unnest()
3137                or self._parse_function()
3138                or self._parse_id_var(any_token=False)
3139            )
3140
3141            while self._match(TokenType.DOT):
3142                this = exp.Dot(
3143                    this=this,
3144                    expression=self._parse_function() or self._parse_id_var(any_token=False),
3145                )
3146
3147        if view:
3148            table = self._parse_id_var(any_token=False)
3149            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
3150            table_alias: t.Optional[exp.TableAlias] = self.expression(
3151                exp.TableAlias, this=table, columns=columns
3152            )
3153        elif isinstance(this, (exp.Subquery, exp.Unnest)) and this.alias:
3154            # We move the alias from the lateral's child node to the lateral itself
3155            table_alias = this.args["alias"].pop()
3156        else:
3157            table_alias = self._parse_table_alias()
3158
3159        return self.expression(
3160            exp.Lateral,
3161            this=this,
3162            view=view,
3163            outer=outer,
3164            alias=table_alias,
3165            cross_apply=cross_apply,
3166        )
3167
3168    def _parse_join_parts(
3169        self,
3170    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
3171        return (
3172            self._match_set(self.JOIN_METHODS) and self._prev,
3173            self._match_set(self.JOIN_SIDES) and self._prev,
3174            self._match_set(self.JOIN_KINDS) and self._prev,
3175        )
3176
3177    def _parse_join(
3178        self, skip_join_token: bool = False, parse_bracket: bool = False
3179    ) -> t.Optional[exp.Join]:
3180        if self._match(TokenType.COMMA):
3181            return self.expression(exp.Join, this=self._parse_table())
3182
3183        index = self._index
3184        method, side, kind = self._parse_join_parts()
3185        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
3186        join = self._match(TokenType.JOIN) or (kind and kind.token_type == TokenType.STRAIGHT_JOIN)
3187
3188        if not skip_join_token and not join:
3189            self._retreat(index)
3190            kind = None
3191            method = None
3192            side = None
3193
3194        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
3195        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
3196
3197        if not skip_join_token and not join and not outer_apply and not cross_apply:
3198            return None
3199
3200        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table(parse_bracket=parse_bracket)}
3201
3202        if method:
3203            kwargs["method"] = method.text
3204        if side:
3205            kwargs["side"] = side.text
3206        if kind:
3207            kwargs["kind"] = kind.text
3208        if hint:
3209            kwargs["hint"] = hint
3210
3211        if self._match(TokenType.MATCH_CONDITION):
3212            kwargs["match_condition"] = self._parse_wrapped(self._parse_comparison)
3213
3214        if self._match(TokenType.ON):
3215            kwargs["on"] = self._parse_assignment()
3216        elif self._match(TokenType.USING):
3217            kwargs["using"] = self._parse_wrapped_id_vars()
3218        elif not isinstance(kwargs["this"], exp.Unnest) and not (
3219            kind and kind.token_type == TokenType.CROSS
3220        ):
3221            index = self._index
3222            joins: t.Optional[list] = list(self._parse_joins())
3223
3224            if joins and self._match(TokenType.ON):
3225                kwargs["on"] = self._parse_assignment()
3226            elif joins and self._match(TokenType.USING):
3227                kwargs["using"] = self._parse_wrapped_id_vars()
3228            else:
3229                joins = None
3230                self._retreat(index)
3231
3232            kwargs["this"].set("joins", joins if joins else None)
3233
3234        comments = [c for token in (method, side, kind) if token for c in token.comments]
3235        return self.expression(exp.Join, comments=comments, **kwargs)
3236
3237    def _parse_opclass(self) -> t.Optional[exp.Expression]:
3238        this = self._parse_assignment()
3239
3240        if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
3241            return this
3242
3243        if not self._match_set(self.OPTYPE_FOLLOW_TOKENS, advance=False):
3244            return self.expression(exp.Opclass, this=this, expression=self._parse_table_parts())
3245
3246        return this
3247
3248    def _parse_index_params(self) -> exp.IndexParameters:
3249        using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
3250
3251        if self._match(TokenType.L_PAREN, advance=False):
3252            columns = self._parse_wrapped_csv(self._parse_with_operator)
3253        else:
3254            columns = None
3255
3256        include = self._parse_wrapped_id_vars() if self._match_text_seq("INCLUDE") else None
3257        partition_by = self._parse_partition_by()
3258        with_storage = self._match(TokenType.WITH) and self._parse_wrapped_properties()
3259        tablespace = (
3260            self._parse_var(any_token=True)
3261            if self._match_text_seq("USING", "INDEX", "TABLESPACE")
3262            else None
3263        )
3264        where = self._parse_where()
3265
3266        on = self._parse_field() if self._match(TokenType.ON) else None
3267
3268        return self.expression(
3269            exp.IndexParameters,
3270            using=using,
3271            columns=columns,
3272            include=include,
3273            partition_by=partition_by,
3274            where=where,
3275            with_storage=with_storage,
3276            tablespace=tablespace,
3277            on=on,
3278        )
3279
3280    def _parse_index(
3281        self, index: t.Optional[exp.Expression] = None, anonymous: bool = False
3282    ) -> t.Optional[exp.Index]:
3283        if index or anonymous:
3284            unique = None
3285            primary = None
3286            amp = None
3287
3288            self._match(TokenType.ON)
3289            self._match(TokenType.TABLE)  # hive
3290            table = self._parse_table_parts(schema=True)
3291        else:
3292            unique = self._match(TokenType.UNIQUE)
3293            primary = self._match_text_seq("PRIMARY")
3294            amp = self._match_text_seq("AMP")
3295
3296            if not self._match(TokenType.INDEX):
3297                return None
3298
3299            index = self._parse_id_var()
3300            table = None
3301
3302        params = self._parse_index_params()
3303
3304        return self.expression(
3305            exp.Index,
3306            this=index,
3307            table=table,
3308            unique=unique,
3309            primary=primary,
3310            amp=amp,
3311            params=params,
3312        )
3313
3314    def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
3315        hints: t.List[exp.Expression] = []
3316        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
3317            # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
3318            hints.append(
3319                self.expression(
3320                    exp.WithTableHint,
3321                    expressions=self._parse_csv(
3322                        lambda: self._parse_function() or self._parse_var(any_token=True)
3323                    ),
3324                )
3325            )
3326            self._match_r_paren()
3327        else:
3328            # https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
3329            while self._match_set(self.TABLE_INDEX_HINT_TOKENS):
3330                hint = exp.IndexTableHint(this=self._prev.text.upper())
3331
3332                self._match_set((TokenType.INDEX, TokenType.KEY))
3333                if self._match(TokenType.FOR):
3334                    hint.set("target", self._advance_any() and self._prev.text.upper())
3335
3336                hint.set("expressions", self._parse_wrapped_id_vars())
3337                hints.append(hint)
3338
3339        return hints or None
3340
3341    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
3342        return (
3343            (not schema and self._parse_function(optional_parens=False))
3344            or self._parse_id_var(any_token=False)
3345            or self._parse_string_as_identifier()
3346            or self._parse_placeholder()
3347        )
3348
3349    def _parse_table_parts(
3350        self, schema: bool = False, is_db_reference: bool = False, wildcard: bool = False
3351    ) -> exp.Table:
3352        catalog = None
3353        db = None
3354        table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
3355
3356        while self._match(TokenType.DOT):
3357            if catalog:
3358                # This allows nesting the table in arbitrarily many dot expressions if needed
3359                table = self.expression(
3360                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
3361                )
3362            else:
3363                catalog = db
3364                db = table
3365                # "" used for tsql FROM a..b case
3366                table = self._parse_table_part(schema=schema) or ""
3367
3368        if (
3369            wildcard
3370            and self._is_connected()
3371            and (isinstance(table, exp.Identifier) or not table)
3372            and self._match(TokenType.STAR)
3373        ):
3374            if isinstance(table, exp.Identifier):
3375                table.args["this"] += "*"
3376            else:
3377                table = exp.Identifier(this="*")
3378
3379        # We bubble up comments from the Identifier to the Table
3380        comments = table.pop_comments() if isinstance(table, exp.Expression) else None
3381
3382        if is_db_reference:
3383            catalog = db
3384            db = table
3385            table = None
3386
3387        if not table and not is_db_reference:
3388            self.raise_error(f"Expected table name but got {self._curr}")
3389        if not db and is_db_reference:
3390            self.raise_error(f"Expected database name but got {self._curr}")
3391
3392        table = self.expression(
3393            exp.Table,
3394            comments=comments,
3395            this=table,
3396            db=db,
3397            catalog=catalog,
3398        )
3399
3400        changes = self._parse_changes()
3401        if changes:
3402            table.set("changes", changes)
3403
3404        at_before = self._parse_historical_data()
3405        if at_before:
3406            table.set("when", at_before)
3407
3408        pivots = self._parse_pivots()
3409        if pivots:
3410            table.set("pivots", pivots)
3411
3412        return table
3413
3414    def _parse_table(
3415        self,
3416        schema: bool = False,
3417        joins: bool = False,
3418        alias_tokens: t.Optional[t.Collection[TokenType]] = None,
3419        parse_bracket: bool = False,
3420        is_db_reference: bool = False,
3421        parse_partition: bool = False,
3422    ) -> t.Optional[exp.Expression]:
3423        lateral = self._parse_lateral()
3424        if lateral:
3425            return lateral
3426
3427        unnest = self._parse_unnest()
3428        if unnest:
3429            return unnest
3430
3431        values = self._parse_derived_table_values()
3432        if values:
3433            return values
3434
3435        subquery = self._parse_select(table=True)
3436        if subquery:
3437            if not subquery.args.get("pivots"):
3438                subquery.set("pivots", self._parse_pivots())
3439            return subquery
3440
3441        bracket = parse_bracket and self._parse_bracket(None)
3442        bracket = self.expression(exp.Table, this=bracket) if bracket else None
3443
3444        rows_from = self._match_text_seq("ROWS", "FROM") and self._parse_wrapped_csv(
3445            self._parse_table
3446        )
3447        rows_from = self.expression(exp.Table, rows_from=rows_from) if rows_from else None
3448
3449        only = self._match(TokenType.ONLY)
3450
3451        this = t.cast(
3452            exp.Expression,
3453            bracket
3454            or rows_from
3455            or self._parse_bracket(
3456                self._parse_table_parts(schema=schema, is_db_reference=is_db_reference)
3457            ),
3458        )
3459
3460        if only:
3461            this.set("only", only)
3462
3463        # Postgres supports a wildcard (table) suffix operator, which is a no-op in this context
3464        self._match_text_seq("*")
3465
3466        parse_partition = parse_partition or self.SUPPORTS_PARTITION_SELECTION
3467        if parse_partition and self._match(TokenType.PARTITION, advance=False):
3468            this.set("partition", self._parse_partition())
3469
3470        if schema:
3471            return self._parse_schema(this=this)
3472
3473        version = self._parse_version()
3474
3475        if version:
3476            this.set("version", version)
3477
3478        if self.dialect.ALIAS_POST_TABLESAMPLE:
3479            table_sample = self._parse_table_sample()
3480
3481        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
3482        if alias:
3483            this.set("alias", alias)
3484
3485        if isinstance(this, exp.Table) and self._match_text_seq("AT"):
3486            return self.expression(
3487                exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
3488            )
3489
3490        this.set("hints", self._parse_table_hints())
3491
3492        if not this.args.get("pivots"):
3493            this.set("pivots", self._parse_pivots())
3494
3495        if not self.dialect.ALIAS_POST_TABLESAMPLE:
3496            table_sample = self._parse_table_sample()
3497
3498        if table_sample:
3499            table_sample.set("this", this)
3500            this = table_sample
3501
3502        if joins:
3503            for join in self._parse_joins():
3504                this.append("joins", join)
3505
3506        if self._match_pair(TokenType.WITH, TokenType.ORDINALITY):
3507            this.set("ordinality", True)
3508            this.set("alias", self._parse_table_alias())
3509
3510        return this
3511
3512    def _parse_version(self) -> t.Optional[exp.Version]:
3513        if self._match(TokenType.TIMESTAMP_SNAPSHOT):
3514            this = "TIMESTAMP"
3515        elif self._match(TokenType.VERSION_SNAPSHOT):
3516            this = "VERSION"
3517        else:
3518            return None
3519
3520        if self._match_set((TokenType.FROM, TokenType.BETWEEN)):
3521            kind = self._prev.text.upper()
3522            start = self._parse_bitwise()
3523            self._match_texts(("TO", "AND"))
3524            end = self._parse_bitwise()
3525            expression: t.Optional[exp.Expression] = self.expression(
3526                exp.Tuple, expressions=[start, end]
3527            )
3528        elif self._match_text_seq("CONTAINED", "IN"):
3529            kind = "CONTAINED IN"
3530            expression = self.expression(
3531                exp.Tuple, expressions=self._parse_wrapped_csv(self._parse_bitwise)
3532            )
3533        elif self._match(TokenType.ALL):
3534            kind = "ALL"
3535            expression = None
3536        else:
3537            self._match_text_seq("AS", "OF")
3538            kind = "AS OF"
3539            expression = self._parse_type()
3540
3541        return self.expression(exp.Version, this=this, expression=expression, kind=kind)
3542
3543    def _parse_historical_data(self) -> t.Optional[exp.HistoricalData]:
3544        # https://docs.snowflake.com/en/sql-reference/constructs/at-before
3545        index = self._index
3546        historical_data = None
3547        if self._match_texts(self.HISTORICAL_DATA_PREFIX):
3548            this = self._prev.text.upper()
3549            kind = (
3550                self._match(TokenType.L_PAREN)
3551                and self._match_texts(self.HISTORICAL_DATA_KIND)
3552                and self._prev.text.upper()
3553            )
3554            expression = self._match(TokenType.FARROW) and self._parse_bitwise()
3555
3556            if expression:
3557                self._match_r_paren()
3558                historical_data = self.expression(
3559                    exp.HistoricalData, this=this, kind=kind, expression=expression
3560                )
3561            else:
3562                self._retreat(index)
3563
3564        return historical_data
3565
3566    def _parse_changes(self) -> t.Optional[exp.Changes]:
3567        if not self._match_text_seq("CHANGES", "(", "INFORMATION", "=>"):
3568            return None
3569
3570        information = self._parse_var(any_token=True)
3571        self._match_r_paren()
3572
3573        return self.expression(
3574            exp.Changes,
3575            information=information,
3576            at_before=self._parse_historical_data(),
3577            end=self._parse_historical_data(),
3578        )
3579
3580    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
3581        if not self._match(TokenType.UNNEST):
3582            return None
3583
3584        expressions = self._parse_wrapped_csv(self._parse_equality)
3585        offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
3586
3587        alias = self._parse_table_alias() if with_alias else None
3588
3589        if alias:
3590            if self.dialect.UNNEST_COLUMN_ONLY:
3591                if alias.args.get("columns"):
3592                    self.raise_error("Unexpected extra column alias in unnest.")
3593
3594                alias.set("columns", [alias.this])
3595                alias.set("this", None)
3596
3597            columns = alias.args.get("columns") or []
3598            if offset and len(expressions) < len(columns):
3599                offset = columns.pop()
3600
3601        if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
3602            self._match(TokenType.ALIAS)
3603            offset = self._parse_id_var(
3604                any_token=False, tokens=self.UNNEST_OFFSET_ALIAS_TOKENS
3605            ) or exp.to_identifier("offset")
3606
3607        return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
3608
3609    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
3610        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
3611        if not is_derived and not self._match_text_seq("VALUES"):
3612            return None
3613
3614        expressions = self._parse_csv(self._parse_value)
3615        alias = self._parse_table_alias()
3616
3617        if is_derived:
3618            self._match_r_paren()
3619
3620        return self.expression(
3621            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
3622        )
3623
3624    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
3625        if not self._match(TokenType.TABLE_SAMPLE) and not (
3626            as_modifier and self._match_text_seq("USING", "SAMPLE")
3627        ):
3628            return None
3629
3630        bucket_numerator = None
3631        bucket_denominator = None
3632        bucket_field = None
3633        percent = None
3634        size = None
3635        seed = None
3636
3637        method = self._parse_var(tokens=(TokenType.ROW,), upper=True)
3638        matched_l_paren = self._match(TokenType.L_PAREN)
3639
3640        if self.TABLESAMPLE_CSV:
3641            num = None
3642            expressions = self._parse_csv(self._parse_primary)
3643        else:
3644            expressions = None
3645            num = (
3646                self._parse_factor()
3647                if self._match(TokenType.NUMBER, advance=False)
3648                else self._parse_primary() or self._parse_placeholder()
3649            )
3650
3651        if self._match_text_seq("BUCKET"):
3652            bucket_numerator = self._parse_number()
3653            self._match_text_seq("OUT", "OF")
3654            bucket_denominator = bucket_denominator = self._parse_number()
3655            self._match(TokenType.ON)
3656            bucket_field = self._parse_field()
3657        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
3658            percent = num
3659        elif self._match(TokenType.ROWS) or not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
3660            size = num
3661        else:
3662            percent = num
3663
3664        if matched_l_paren:
3665            self._match_r_paren()
3666
3667        if self._match(TokenType.L_PAREN):
3668            method = self._parse_var(upper=True)
3669            seed = self._match(TokenType.COMMA) and self._parse_number()
3670            self._match_r_paren()
3671        elif self._match_texts(("SEED", "REPEATABLE")):
3672            seed = self._parse_wrapped(self._parse_number)
3673
3674        if not method and self.DEFAULT_SAMPLING_METHOD:
3675            method = exp.var(self.DEFAULT_SAMPLING_METHOD)
3676
3677        return self.expression(
3678            exp.TableSample,
3679            expressions=expressions,
3680            method=method,
3681            bucket_numerator=bucket_numerator,
3682            bucket_denominator=bucket_denominator,
3683            bucket_field=bucket_field,
3684            percent=percent,
3685            size=size,
3686            seed=seed,
3687        )
3688
3689    def _parse_pivots(self) -> t.Optional[t.List[exp.Pivot]]:
3690        return list(iter(self._parse_pivot, None)) or None
3691
3692    def _parse_joins(self) -> t.Iterator[exp.Join]:
3693        return iter(self._parse_join, None)
3694
3695    # https://duckdb.org/docs/sql/statements/pivot
3696    def _parse_simplified_pivot(self) -> exp.Pivot:
3697        def _parse_on() -> t.Optional[exp.Expression]:
3698            this = self._parse_bitwise()
3699            return self._parse_in(this) if self._match(TokenType.IN) else this
3700
3701        this = self._parse_table()
3702        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
3703        using = self._match(TokenType.USING) and self._parse_csv(
3704            lambda: self._parse_alias(self._parse_function())
3705        )
3706        group = self._parse_group()
3707        return self.expression(
3708            exp.Pivot, this=this, expressions=expressions, using=using, group=group
3709        )
3710
3711    def _parse_pivot_in(self) -> exp.In:
3712        def _parse_aliased_expression() -> t.Optional[exp.Expression]:
3713            this = self._parse_assignment()
3714
3715            self._match(TokenType.ALIAS)
3716            alias = self._parse_field()
3717            if alias:
3718                return self.expression(exp.PivotAlias, this=this, alias=alias)
3719
3720            return this
3721
3722        value = self._parse_column()
3723
3724        if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
3725            self.raise_error("Expecting IN (")
3726
3727        aliased_expressions = self._parse_csv(_parse_aliased_expression)
3728
3729        self._match_r_paren()
3730        return self.expression(exp.In, this=value, expressions=aliased_expressions)
3731
3732    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
3733        index = self._index
3734        include_nulls = None
3735
3736        if self._match(TokenType.PIVOT):
3737            unpivot = False
3738        elif self._match(TokenType.UNPIVOT):
3739            unpivot = True
3740
3741            # https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
3742            if self._match_text_seq("INCLUDE", "NULLS"):
3743                include_nulls = True
3744            elif self._match_text_seq("EXCLUDE", "NULLS"):
3745                include_nulls = False
3746        else:
3747            return None
3748
3749        expressions = []
3750
3751        if not self._match(TokenType.L_PAREN):
3752            self._retreat(index)
3753            return None
3754
3755        if unpivot:
3756            expressions = self._parse_csv(self._parse_column)
3757        else:
3758            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
3759
3760        if not expressions:
3761            self.raise_error("Failed to parse PIVOT's aggregation list")
3762
3763        if not self._match(TokenType.FOR):
3764            self.raise_error("Expecting FOR")
3765
3766        field = self._parse_pivot_in()
3767
3768        self._match_r_paren()
3769
3770        pivot = self.expression(
3771            exp.Pivot,
3772            expressions=expressions,
3773            field=field,
3774            unpivot=unpivot,
3775            include_nulls=include_nulls,
3776        )
3777
3778        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
3779            pivot.set("alias", self._parse_table_alias())
3780
3781        if not unpivot:
3782            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
3783
3784            columns: t.List[exp.Expression] = []
3785            for fld in pivot.args["field"].expressions:
3786                field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
3787                for name in names:
3788                    if self.PREFIXED_PIVOT_COLUMNS:
3789                        name = f"{name}_{field_name}" if name else field_name
3790                    else:
3791                        name = f"{field_name}_{name}" if name else field_name
3792
3793                    columns.append(exp.to_identifier(name))
3794
3795            pivot.set("columns", columns)
3796
3797        return pivot
3798
3799    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
3800        return [agg.alias for agg in aggregations]
3801
3802    def _parse_prewhere(self, skip_where_token: bool = False) -> t.Optional[exp.PreWhere]:
3803        if not skip_where_token and not self._match(TokenType.PREWHERE):
3804            return None
3805
3806        return self.expression(
3807            exp.PreWhere, comments=self._prev_comments, this=self._parse_assignment()
3808        )
3809
3810    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
3811        if not skip_where_token and not self._match(TokenType.WHERE):
3812            return None
3813
3814        return self.expression(
3815            exp.Where, comments=self._prev_comments, this=self._parse_assignment()
3816        )
3817
3818    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
3819        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
3820            return None
3821
3822        elements: t.Dict[str, t.Any] = defaultdict(list)
3823
3824        if self._match(TokenType.ALL):
3825            elements["all"] = True
3826        elif self._match(TokenType.DISTINCT):
3827            elements["all"] = False
3828
3829        while True:
3830            expressions = self._parse_csv(
3831                lambda: None
3832                if self._match_set((TokenType.CUBE, TokenType.ROLLUP), advance=False)
3833                else self._parse_assignment()
3834            )
3835            if expressions:
3836                elements["expressions"].extend(expressions)
3837
3838            grouping_sets = self._parse_grouping_sets()
3839            if grouping_sets:
3840                elements["grouping_sets"].extend(grouping_sets)
3841
3842            rollup = None
3843            cube = None
3844            totals = None
3845
3846            index = self._index
3847            with_ = self._match(TokenType.WITH)
3848            if self._match(TokenType.ROLLUP):
3849                rollup = with_ or self._parse_wrapped_csv(self._parse_column)
3850                elements["rollup"].extend(ensure_list(rollup))
3851
3852            if self._match(TokenType.CUBE):
3853                cube = with_ or self._parse_wrapped_csv(self._parse_column)
3854                elements["cube"].extend(ensure_list(cube))
3855
3856            if self._match_text_seq("TOTALS"):
3857                totals = True
3858                elements["totals"] = True  # type: ignore
3859
3860            if not (grouping_sets or rollup or cube or totals):
3861                if with_:
3862                    self._retreat(index)
3863                break
3864
3865        return self.expression(exp.Group, **elements)  # type: ignore
3866
3867    def _parse_grouping_sets(self) -> t.Optional[t.List[exp.Expression]]:
3868        if not self._match(TokenType.GROUPING_SETS):
3869            return None
3870
3871        return self._parse_wrapped_csv(self._parse_grouping_set)
3872
3873    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
3874        if self._match(TokenType.L_PAREN):
3875            grouping_set = self._parse_csv(self._parse_column)
3876            self._match_r_paren()
3877            return self.expression(exp.Tuple, expressions=grouping_set)
3878
3879        return self._parse_column()
3880
3881    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
3882        if not skip_having_token and not self._match(TokenType.HAVING):
3883            return None
3884        return self.expression(exp.Having, this=self._parse_assignment())
3885
3886    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
3887        if not self._match(TokenType.QUALIFY):
3888            return None
3889        return self.expression(exp.Qualify, this=self._parse_assignment())
3890
3891    def _parse_connect(self, skip_start_token: bool = False) -> t.Optional[exp.Connect]:
3892        if skip_start_token:
3893            start = None
3894        elif self._match(TokenType.START_WITH):
3895            start = self._parse_assignment()
3896        else:
3897            return None
3898
3899        self._match(TokenType.CONNECT_BY)
3900        nocycle = self._match_text_seq("NOCYCLE")
3901        self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
3902            exp.Prior, this=self._parse_bitwise()
3903        )
3904        connect = self._parse_assignment()
3905        self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
3906
3907        if not start and self._match(TokenType.START_WITH):
3908            start = self._parse_assignment()
3909
3910        return self.expression(exp.Connect, start=start, connect=connect, nocycle=nocycle)
3911
3912    def _parse_name_as_expression(self) -> exp.Alias:
3913        return self.expression(
3914            exp.Alias,
3915            alias=self._parse_id_var(any_token=True),
3916            this=self._match(TokenType.ALIAS) and self._parse_assignment(),
3917        )
3918
3919    def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
3920        if self._match_text_seq("INTERPOLATE"):
3921            return self._parse_wrapped_csv(self._parse_name_as_expression)
3922        return None
3923
3924    def _parse_order(
3925        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
3926    ) -> t.Optional[exp.Expression]:
3927        siblings = None
3928        if not skip_order_token and not self._match(TokenType.ORDER_BY):
3929            if not self._match(TokenType.ORDER_SIBLINGS_BY):
3930                return this
3931
3932            siblings = True
3933
3934        return self.expression(
3935            exp.Order,
3936            this=this,
3937            expressions=self._parse_csv(self._parse_ordered),
3938            interpolate=self._parse_interpolate(),
3939            siblings=siblings,
3940        )
3941
3942    def _parse_sort(self, exp_class: t.Type[E], token: TokenType) -> t.Optional[E]:
3943        if not self._match(token):
3944            return None
3945        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
3946
3947    def _parse_ordered(
3948        self, parse_method: t.Optional[t.Callable] = None
3949    ) -> t.Optional[exp.Ordered]:
3950        this = parse_method() if parse_method else self._parse_assignment()
3951        if not this:
3952            return None
3953
3954        if this.name.upper() == "ALL" and self.dialect.SUPPORTS_ORDER_BY_ALL:
3955            this = exp.var("ALL")
3956
3957        asc = self._match(TokenType.ASC)
3958        desc = self._match(TokenType.DESC) or (asc and False)
3959
3960        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
3961        is_nulls_last = self._match_text_seq("NULLS", "LAST")
3962
3963        nulls_first = is_nulls_first or False
3964        explicitly_null_ordered = is_nulls_first or is_nulls_last
3965
3966        if (
3967            not explicitly_null_ordered
3968            and (
3969                (not desc and self.dialect.NULL_ORDERING == "nulls_are_small")
3970                or (desc and self.dialect.NULL_ORDERING != "nulls_are_small")
3971            )
3972            and self.dialect.NULL_ORDERING != "nulls_are_last"
3973        ):
3974            nulls_first = True
3975
3976        if self._match_text_seq("WITH", "FILL"):
3977            with_fill = self.expression(
3978                exp.WithFill,
3979                **{  # type: ignore
3980                    "from": self._match(TokenType.FROM) and self._parse_bitwise(),
3981                    "to": self._match_text_seq("TO") and self._parse_bitwise(),
3982                    "step": self._match_text_seq("STEP") and self._parse_bitwise(),
3983                },
3984            )
3985        else:
3986            with_fill = None
3987
3988        return self.expression(
3989            exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
3990        )
3991
3992    def _parse_limit(
3993        self,
3994        this: t.Optional[exp.Expression] = None,
3995        top: bool = False,
3996        skip_limit_token: bool = False,
3997    ) -> t.Optional[exp.Expression]:
3998        if skip_limit_token or self._match(TokenType.TOP if top else TokenType.LIMIT):
3999            comments = self._prev_comments
4000            if top:
4001                limit_paren = self._match(TokenType.L_PAREN)
4002                expression = self._parse_term() if limit_paren else self._parse_number()
4003
4004                if limit_paren:
4005                    self._match_r_paren()
4006            else:
4007                expression = self._parse_term()
4008
4009            if self._match(TokenType.COMMA):
4010                offset = expression
4011                expression = self._parse_term()
4012            else:
4013                offset = None
4014
4015            limit_exp = self.expression(
4016                exp.Limit,
4017                this=this,
4018                expression=expression,
4019                offset=offset,
4020                comments=comments,
4021                expressions=self._parse_limit_by(),
4022            )
4023
4024            return limit_exp
4025
4026        if self._match(TokenType.FETCH):
4027            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
4028            direction = self._prev.text.upper() if direction else "FIRST"
4029
4030            count = self._parse_field(tokens=self.FETCH_TOKENS)
4031            percent = self._match(TokenType.PERCENT)
4032
4033            self._match_set((TokenType.ROW, TokenType.ROWS))
4034
4035            only = self._match_text_seq("ONLY")
4036            with_ties = self._match_text_seq("WITH", "TIES")
4037
4038            if only and with_ties:
4039                self.raise_error("Cannot specify both ONLY and WITH TIES in FETCH clause")
4040
4041            return self.expression(
4042                exp.Fetch,
4043                direction=direction,
4044                count=count,
4045                percent=percent,
4046                with_ties=with_ties,
4047            )
4048
4049        return this
4050
4051    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4052        if not self._match(TokenType.OFFSET):
4053            return this
4054
4055        count = self._parse_term()
4056        self._match_set((TokenType.ROW, TokenType.ROWS))
4057
4058        return self.expression(
4059            exp.Offset, this=this, expression=count, expressions=self._parse_limit_by()
4060        )
4061
4062    def _parse_limit_by(self) -> t.Optional[t.List[exp.Expression]]:
4063        return self._match_text_seq("BY") and self._parse_csv(self._parse_bitwise)
4064
4065    def _parse_locks(self) -> t.List[exp.Lock]:
4066        locks = []
4067        while True:
4068            if self._match_text_seq("FOR", "UPDATE"):
4069                update = True
4070            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
4071                "LOCK", "IN", "SHARE", "MODE"
4072            ):
4073                update = False
4074            else:
4075                break
4076
4077            expressions = None
4078            if self._match_text_seq("OF"):
4079                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
4080
4081            wait: t.Optional[bool | exp.Expression] = None
4082            if self._match_text_seq("NOWAIT"):
4083                wait = True
4084            elif self._match_text_seq("WAIT"):
4085                wait = self._parse_primary()
4086            elif self._match_text_seq("SKIP", "LOCKED"):
4087                wait = False
4088
4089            locks.append(
4090                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
4091            )
4092
4093        return locks
4094
4095    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4096        while this and self._match_set(self.SET_OPERATIONS):
4097            token_type = self._prev.token_type
4098
4099            if token_type == TokenType.UNION:
4100                operation: t.Type[exp.SetOperation] = exp.Union
4101            elif token_type == TokenType.EXCEPT:
4102                operation = exp.Except
4103            else:
4104                operation = exp.Intersect
4105
4106            comments = self._prev.comments
4107            distinct = self._match(TokenType.DISTINCT) or not self._match(TokenType.ALL)
4108            by_name = self._match_text_seq("BY", "NAME")
4109            expression = self._parse_select(nested=True, parse_set_operation=False)
4110
4111            this = self.expression(
4112                operation,
4113                comments=comments,
4114                this=this,
4115                distinct=distinct,
4116                by_name=by_name,
4117                expression=expression,
4118            )
4119
4120        if isinstance(this, exp.SetOperation) and self.MODIFIERS_ATTACHED_TO_SET_OP:
4121            expression = this.expression
4122
4123            if expression:
4124                for arg in self.SET_OP_MODIFIERS:
4125                    expr = expression.args.get(arg)
4126                    if expr:
4127                        this.set(arg, expr.pop())
4128
4129        return this
4130
4131    def _parse_expression(self) -> t.Optional[exp.Expression]:
4132        return self._parse_alias(self._parse_assignment())
4133
4134    def _parse_assignment(self) -> t.Optional[exp.Expression]:
4135        this = self._parse_disjunction()
4136
4137        while self._match_set(self.ASSIGNMENT):
4138            this = self.expression(
4139                self.ASSIGNMENT[self._prev.token_type],
4140                this=this,
4141                comments=self._prev_comments,
4142                expression=self._parse_assignment(),
4143            )
4144
4145        return this
4146
4147    def _parse_disjunction(self) -> t.Optional[exp.Expression]:
4148        return self._parse_tokens(self._parse_conjunction, self.DISJUNCTION)
4149
4150    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
4151        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
4152
4153    def _parse_equality(self) -> t.Optional[exp.Expression]:
4154        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
4155
4156    def _parse_comparison(self) -> t.Optional[exp.Expression]:
4157        return self._parse_tokens(self._parse_range, self.COMPARISON)
4158
4159    def _parse_range(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4160        this = this or self._parse_bitwise()
4161        negate = self._match(TokenType.NOT)
4162
4163        if self._match_set(self.RANGE_PARSERS):
4164            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
4165            if not expression:
4166                return this
4167
4168            this = expression
4169        elif self._match(TokenType.ISNULL):
4170            this = self.expression(exp.Is, this=this, expression=exp.Null())
4171
4172        # Postgres supports ISNULL and NOTNULL for conditions.
4173        # https://blog.andreiavram.ro/postgresql-null-composite-type/
4174        if self._match(TokenType.NOTNULL):
4175            this = self.expression(exp.Is, this=this, expression=exp.Null())
4176            this = self.expression(exp.Not, this=this)
4177
4178        if negate:
4179            this = self.expression(exp.Not, this=this)
4180
4181        if self._match(TokenType.IS):
4182            this = self._parse_is(this)
4183
4184        return this
4185
4186    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4187        index = self._index - 1
4188        negate = self._match(TokenType.NOT)
4189
4190        if self._match_text_seq("DISTINCT", "FROM"):
4191            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
4192            return self.expression(klass, this=this, expression=self._parse_bitwise())
4193
4194        expression = self._parse_null() or self._parse_boolean()
4195        if not expression:
4196            self._retreat(index)
4197            return None
4198
4199        this = self.expression(exp.Is, this=this, expression=expression)
4200        return self.expression(exp.Not, this=this) if negate else this
4201
4202    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
4203        unnest = self._parse_unnest(with_alias=False)
4204        if unnest:
4205            this = self.expression(exp.In, this=this, unnest=unnest)
4206        elif self._match_set((TokenType.L_PAREN, TokenType.L_BRACKET)):
4207            matched_l_paren = self._prev.token_type == TokenType.L_PAREN
4208            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
4209
4210            if len(expressions) == 1 and isinstance(expressions[0], exp.Query):
4211                this = self.expression(exp.In, this=this, query=expressions[0].subquery(copy=False))
4212            else:
4213                this = self.expression(exp.In, this=this, expressions=expressions)
4214
4215            if matched_l_paren:
4216                self._match_r_paren(this)
4217            elif not self._match(TokenType.R_BRACKET, expression=this):
4218                self.raise_error("Expecting ]")
4219        else:
4220            this = self.expression(exp.In, this=this, field=self._parse_field())
4221
4222        return this
4223
4224    def _parse_between(self, this: t.Optional[exp.Expression]) -> exp.Between:
4225        low = self._parse_bitwise()
4226        self._match(TokenType.AND)
4227        high = self._parse_bitwise()
4228        return self.expression(exp.Between, this=this, low=low, high=high)
4229
4230    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4231        if not self._match(TokenType.ESCAPE):
4232            return this
4233        return self.expression(exp.Escape, this=this, expression=self._parse_string())
4234
4235    def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Add | exp.Interval]:
4236        index = self._index
4237
4238        if not self._match(TokenType.INTERVAL) and match_interval:
4239            return None
4240
4241        if self._match(TokenType.STRING, advance=False):
4242            this = self._parse_primary()
4243        else:
4244            this = self._parse_term()
4245
4246        if not this or (
4247            isinstance(this, exp.Column)
4248            and not this.table
4249            and not this.this.quoted
4250            and this.name.upper() == "IS"
4251        ):
4252            self._retreat(index)
4253            return None
4254
4255        unit = self._parse_function() or (
4256            not self._match(TokenType.ALIAS, advance=False)
4257            and self._parse_var(any_token=True, upper=True)
4258        )
4259
4260        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
4261        # each INTERVAL expression into this canonical form so it's easy to transpile
4262        if this and this.is_number:
4263            this = exp.Literal.string(this.to_py())
4264        elif this and this.is_string:
4265            parts = exp.INTERVAL_STRING_RE.findall(this.name)
4266            if len(parts) == 1:
4267                if unit:
4268                    # Unconsume the eagerly-parsed unit, since the real unit was part of the string
4269                    self._retreat(self._index - 1)
4270
4271                this = exp.Literal.string(parts[0][0])
4272                unit = self.expression(exp.Var, this=parts[0][1].upper())
4273
4274        if self.INTERVAL_SPANS and self._match_text_seq("TO"):
4275            unit = self.expression(
4276                exp.IntervalSpan, this=unit, expression=self._parse_var(any_token=True, upper=True)
4277            )
4278
4279        interval = self.expression(exp.Interval, this=this, unit=unit)
4280
4281        index = self._index
4282        self._match(TokenType.PLUS)
4283
4284        # Convert INTERVAL 'val_1' unit_1 [+] ... [+] 'val_n' unit_n into a sum of intervals
4285        if self._match_set((TokenType.STRING, TokenType.NUMBER), advance=False):
4286            return self.expression(
4287                exp.Add, this=interval, expression=self._parse_interval(match_interval=False)
4288            )
4289
4290        self._retreat(index)
4291        return interval
4292
4293    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
4294        this = self._parse_term()
4295
4296        while True:
4297            if self._match_set(self.BITWISE):
4298                this = self.expression(
4299                    self.BITWISE[self._prev.token_type],
4300                    this=this,
4301                    expression=self._parse_term(),
4302                )
4303            elif self.dialect.DPIPE_IS_STRING_CONCAT and self._match(TokenType.DPIPE):
4304                this = self.expression(
4305                    exp.DPipe,
4306                    this=this,
4307                    expression=self._parse_term(),
4308                    safe=not self.dialect.STRICT_STRING_CONCAT,
4309                )
4310            elif self._match(TokenType.DQMARK):
4311                this = self.expression(exp.Coalesce, this=this, expressions=self._parse_term())
4312            elif self._match_pair(TokenType.LT, TokenType.LT):
4313                this = self.expression(
4314                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
4315                )
4316            elif self._match_pair(TokenType.GT, TokenType.GT):
4317                this = self.expression(
4318                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
4319                )
4320            else:
4321                break
4322
4323        return this
4324
4325    def _parse_term(self) -> t.Optional[exp.Expression]:
4326        return self._parse_tokens(self._parse_factor, self.TERM)
4327
4328    def _parse_factor(self) -> t.Optional[exp.Expression]:
4329        parse_method = self._parse_exponent if self.EXPONENT else self._parse_unary
4330        this = parse_method()
4331
4332        while self._match_set(self.FACTOR):
4333            klass = self.FACTOR[self._prev.token_type]
4334            comments = self._prev_comments
4335            expression = parse_method()
4336
4337            if not expression and klass is exp.IntDiv and self._prev.text.isalpha():
4338                self._retreat(self._index - 1)
4339                return this
4340
4341            this = self.expression(klass, this=this, comments=comments, expression=expression)
4342
4343            if isinstance(this, exp.Div):
4344                this.args["typed"] = self.dialect.TYPED_DIVISION
4345                this.args["safe"] = self.dialect.SAFE_DIVISION
4346
4347        return this
4348
4349    def _parse_exponent(self) -> t.Optional[exp.Expression]:
4350        return self._parse_tokens(self._parse_unary, self.EXPONENT)
4351
4352    def _parse_unary(self) -> t.Optional[exp.Expression]:
4353        if self._match_set(self.UNARY_PARSERS):
4354            return self.UNARY_PARSERS[self._prev.token_type](self)
4355        return self._parse_at_time_zone(self._parse_type())
4356
4357    def _parse_type(
4358        self, parse_interval: bool = True, fallback_to_identifier: bool = False
4359    ) -> t.Optional[exp.Expression]:
4360        interval = parse_interval and self._parse_interval()
4361        if interval:
4362            return interval
4363
4364        index = self._index
4365        data_type = self._parse_types(check_func=True, allow_identifiers=False)
4366
4367        # parse_types() returns a Cast if we parsed BQ's inline constructor <type>(<values>) e.g.
4368        # STRUCT<a INT, b STRING>(1, 'foo'), which is canonicalized to CAST(<values> AS <type>)
4369        if isinstance(data_type, exp.Cast):
4370            # This constructor can contain ops directly after it, for instance struct unnesting:
4371            # STRUCT<a INT, b STRING>(1, 'foo').* --> CAST(STRUCT(1, 'foo') AS STRUCT<a iNT, b STRING).*
4372            return self._parse_column_ops(data_type)
4373
4374        if data_type:
4375            index2 = self._index
4376            this = self._parse_primary()
4377
4378            if isinstance(this, exp.Literal):
4379                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
4380                if parser:
4381                    return parser(self, this, data_type)
4382
4383                return self.expression(exp.Cast, this=this, to=data_type)
4384
4385            # The expressions arg gets set by the parser when we have something like DECIMAL(38, 0)
4386            # in the input SQL. In that case, we'll produce these tokens: DECIMAL ( 38 , 0 )
4387            #
4388            # If the index difference here is greater than 1, that means the parser itself must have
4389            # consumed additional tokens such as the DECIMAL scale and precision in the above example.
4390            #
4391            # If it's not greater than 1, then it must be 1, because we've consumed at least the type
4392            # keyword, meaning that the expressions arg of the DataType must have gotten set by a
4393            # callable in the TYPE_CONVERTERS mapping. For example, Snowflake converts DECIMAL to
4394            # DECIMAL(38, 0)) in order to facilitate the data type's transpilation.
4395            #
4396            # In these cases, we don't really want to return the converted type, but instead retreat
4397            # and try to parse a Column or Identifier in the section below.
4398            if data_type.expressions and index2 - index > 1:
4399                self._retreat(index2)
4400                return self._parse_column_ops(data_type)
4401
4402            self._retreat(index)
4403
4404        if fallback_to_identifier:
4405            return self._parse_id_var()
4406
4407        this = self._parse_column()
4408        return this and self._parse_column_ops(this)
4409
4410    def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
4411        this = self._parse_type()
4412        if not this:
4413            return None
4414
4415        if isinstance(this, exp.Column) and not this.table:
4416            this = exp.var(this.name.upper())
4417
4418        return self.expression(
4419            exp.DataTypeParam, this=this, expression=self._parse_var(any_token=True)
4420        )
4421
4422    def _parse_types(
4423        self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
4424    ) -> t.Optional[exp.Expression]:
4425        index = self._index
4426
4427        this: t.Optional[exp.Expression] = None
4428        prefix = self._match_text_seq("SYSUDTLIB", ".")
4429
4430        if not self._match_set(self.TYPE_TOKENS):
4431            identifier = allow_identifiers and self._parse_id_var(
4432                any_token=False, tokens=(TokenType.VAR,)
4433            )
4434            if isinstance(identifier, exp.Identifier):
4435                tokens = self.dialect.tokenize(identifier.sql(dialect=self.dialect))
4436
4437                if len(tokens) != 1:
4438                    self.raise_error("Unexpected identifier", self._prev)
4439
4440                if tokens[0].token_type in self.TYPE_TOKENS:
4441                    self._prev = tokens[0]
4442                elif self.dialect.SUPPORTS_USER_DEFINED_TYPES:
4443                    type_name = identifier.name
4444
4445                    while self._match(TokenType.DOT):
4446                        type_name = f"{type_name}.{self._advance_any() and self._prev.text}"
4447
4448                    this = exp.DataType.build(type_name, udt=True)
4449                else:
4450                    self._retreat(self._index - 1)
4451                    return None
4452            else:
4453                return None
4454
4455        type_token = self._prev.token_type
4456
4457        if type_token == TokenType.PSEUDO_TYPE:
4458            return self.expression(exp.PseudoType, this=self._prev.text.upper())
4459
4460        if type_token == TokenType.OBJECT_IDENTIFIER:
4461            return self.expression(exp.ObjectIdentifier, this=self._prev.text.upper())
4462
4463        # https://materialize.com/docs/sql/types/map/
4464        if type_token == TokenType.MAP and self._match(TokenType.L_BRACKET):
4465            key_type = self._parse_types(
4466                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4467            )
4468            if not self._match(TokenType.FARROW):
4469                self._retreat(index)
4470                return None
4471
4472            value_type = self._parse_types(
4473                check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4474            )
4475            if not self._match(TokenType.R_BRACKET):
4476                self._retreat(index)
4477                return None
4478
4479            return exp.DataType(
4480                this=exp.DataType.Type.MAP,
4481                expressions=[key_type, value_type],
4482                nested=True,
4483                prefix=prefix,
4484            )
4485
4486        nested = type_token in self.NESTED_TYPE_TOKENS
4487        is_struct = type_token in self.STRUCT_TYPE_TOKENS
4488        is_aggregate = type_token in self.AGGREGATE_TYPE_TOKENS
4489        expressions = None
4490        maybe_func = False
4491
4492        if self._match(TokenType.L_PAREN):
4493            if is_struct:
4494                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
4495            elif nested:
4496                expressions = self._parse_csv(
4497                    lambda: self._parse_types(
4498                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4499                    )
4500                )
4501            elif type_token in self.ENUM_TYPE_TOKENS:
4502                expressions = self._parse_csv(self._parse_equality)
4503            elif is_aggregate:
4504                func_or_ident = self._parse_function(anonymous=True) or self._parse_id_var(
4505                    any_token=False, tokens=(TokenType.VAR,)
4506                )
4507                if not func_or_ident or not self._match(TokenType.COMMA):
4508                    return None
4509                expressions = self._parse_csv(
4510                    lambda: self._parse_types(
4511                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4512                    )
4513                )
4514                expressions.insert(0, func_or_ident)
4515            else:
4516                expressions = self._parse_csv(self._parse_type_size)
4517
4518                # https://docs.snowflake.com/en/sql-reference/data-types-vector
4519                if type_token == TokenType.VECTOR and len(expressions) == 2:
4520                    expressions[0] = exp.DataType.build(expressions[0].name, dialect=self.dialect)
4521
4522            if not expressions or not self._match(TokenType.R_PAREN):
4523                self._retreat(index)
4524                return None
4525
4526            maybe_func = True
4527
4528        values: t.Optional[t.List[exp.Expression]] = None
4529
4530        if nested and self._match(TokenType.LT):
4531            if is_struct:
4532                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
4533            else:
4534                expressions = self._parse_csv(
4535                    lambda: self._parse_types(
4536                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
4537                    )
4538                )
4539
4540            if not self._match(TokenType.GT):
4541                self.raise_error("Expecting >")
4542
4543            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
4544                values = self._parse_csv(self._parse_assignment)
4545                self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
4546
4547        if type_token in self.TIMESTAMPS:
4548            if self._match_text_seq("WITH", "TIME", "ZONE"):
4549                maybe_func = False
4550                tz_type = (
4551                    exp.DataType.Type.TIMETZ
4552                    if type_token in self.TIMES
4553                    else exp.DataType.Type.TIMESTAMPTZ
4554                )
4555                this = exp.DataType(this=tz_type, expressions=expressions)
4556            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
4557                maybe_func = False
4558                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
4559            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
4560                maybe_func = False
4561        elif type_token == TokenType.INTERVAL:
4562            unit = self._parse_var(upper=True)
4563            if unit:
4564                if self._match_text_seq("TO"):
4565                    unit = exp.IntervalSpan(this=unit, expression=self._parse_var(upper=True))
4566
4567                this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
4568            else:
4569                this = self.expression(exp.DataType, this=exp.DataType.Type.INTERVAL)
4570
4571        if maybe_func and check_func:
4572            index2 = self._index
4573            peek = self._parse_string()
4574
4575            if not peek:
4576                self._retreat(index)
4577                return None
4578
4579            self._retreat(index2)
4580
4581        if not this:
4582            if self._match_text_seq("UNSIGNED"):
4583                unsigned_type_token = self.SIGNED_TO_UNSIGNED_TYPE_TOKEN.get(type_token)
4584                if not unsigned_type_token:
4585                    self.raise_error(f"Cannot convert {type_token.value} to unsigned.")
4586
4587                type_token = unsigned_type_token or type_token
4588
4589            this = exp.DataType(
4590                this=exp.DataType.Type[type_token.value],
4591                expressions=expressions,
4592                nested=nested,
4593                prefix=prefix,
4594            )
4595
4596            # Empty arrays/structs are allowed
4597            if values is not None:
4598                cls = exp.Struct if is_struct else exp.Array
4599                this = exp.cast(cls(expressions=values), this, copy=False)
4600
4601        elif expressions:
4602            this.set("expressions", expressions)
4603
4604        # https://materialize.com/docs/sql/types/list/#type-name
4605        while self._match(TokenType.LIST):
4606            this = exp.DataType(this=exp.DataType.Type.LIST, expressions=[this], nested=True)
4607
4608        index = self._index
4609
4610        # Postgres supports the INT ARRAY[3] syntax as a synonym for INT[3]
4611        matched_array = self._match(TokenType.ARRAY)
4612
4613        while self._curr:
4614            matched_l_bracket = self._match(TokenType.L_BRACKET)
4615            if not matched_l_bracket and not matched_array:
4616                break
4617
4618            matched_array = False
4619            values = self._parse_csv(self._parse_assignment) or None
4620            if (
4621                values
4622                and not schema
4623                and this.is_type(exp.DataType.Type.ARRAY, exp.DataType.Type.MAP)
4624            ):
4625                self._retreat(index)
4626                break
4627
4628            this = exp.DataType(
4629                this=exp.DataType.Type.ARRAY, expressions=[this], values=values, nested=True
4630            )
4631            self._match(TokenType.R_BRACKET)
4632
4633        if self.TYPE_CONVERTERS and isinstance(this.this, exp.DataType.Type):
4634            converter = self.TYPE_CONVERTERS.get(this.this)
4635            if converter:
4636                this = converter(t.cast(exp.DataType, this))
4637
4638        return this
4639
4640    def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
4641        index = self._index
4642
4643        if (
4644            self._curr
4645            and self._next
4646            and self._curr.token_type in self.TYPE_TOKENS
4647            and self._next.token_type in self.TYPE_TOKENS
4648        ):
4649            # Takes care of special cases like `STRUCT<list ARRAY<...>>` where the identifier is also a
4650            # type token. Without this, the list will be parsed as a type and we'll eventually crash
4651            this = self._parse_id_var()
4652        else:
4653            this = (
4654                self._parse_type(parse_interval=False, fallback_to_identifier=True)
4655                or self._parse_id_var()
4656            )
4657
4658        self._match(TokenType.COLON)
4659
4660        if (
4661            type_required
4662            and not isinstance(this, exp.DataType)
4663            and not self._match_set(self.TYPE_TOKENS, advance=False)
4664        ):
4665            self._retreat(index)
4666            return self._parse_types()
4667
4668        return self._parse_column_def(this)
4669
4670    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4671        if not self._match_text_seq("AT", "TIME", "ZONE"):
4672            return this
4673        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
4674
4675    def _parse_column(self) -> t.Optional[exp.Expression]:
4676        this = self._parse_column_reference()
4677        column = self._parse_column_ops(this) if this else self._parse_bracket(this)
4678
4679        if self.dialect.SUPPORTS_COLUMN_JOIN_MARKS and column:
4680            column.set("join_mark", self._match(TokenType.JOIN_MARKER))
4681
4682        return column
4683
4684    def _parse_column_reference(self) -> t.Optional[exp.Expression]:
4685        this = self._parse_field()
4686        if (
4687            not this
4688            and self._match(TokenType.VALUES, advance=False)
4689            and self.VALUES_FOLLOWED_BY_PAREN
4690            and (not self._next or self._next.token_type != TokenType.L_PAREN)
4691        ):
4692            this = self._parse_id_var()
4693
4694        if isinstance(this, exp.Identifier):
4695            # We bubble up comments from the Identifier to the Column
4696            this = self.expression(exp.Column, comments=this.pop_comments(), this=this)
4697
4698        return this
4699
4700    def _parse_colon_as_variant_extract(
4701        self, this: t.Optional[exp.Expression]
4702    ) -> t.Optional[exp.Expression]:
4703        casts = []
4704        json_path = []
4705
4706        while self._match(TokenType.COLON):
4707            start_index = self._index
4708
4709            # Snowflake allows reserved keywords as json keys but advance_any() excludes TokenType.SELECT from any_tokens=True
4710            path = self._parse_column_ops(
4711                self._parse_field(any_token=True, tokens=(TokenType.SELECT,))
4712            )
4713
4714            # The cast :: operator has a lower precedence than the extraction operator :, so
4715            # we rearrange the AST appropriately to avoid casting the JSON path
4716            while isinstance(path, exp.Cast):
4717                casts.append(path.to)
4718                path = path.this
4719
4720            if casts:
4721                dcolon_offset = next(
4722                    i
4723                    for i, t in enumerate(self._tokens[start_index:])
4724                    if t.token_type == TokenType.DCOLON
4725                )
4726                end_token = self._tokens[start_index + dcolon_offset - 1]
4727            else:
4728                end_token = self._prev
4729
4730            if path:
4731                json_path.append(self._find_sql(self._tokens[start_index], end_token))
4732
4733        # The VARIANT extract in Snowflake/Databricks is parsed as a JSONExtract; Snowflake uses the json_path in GET_PATH() while
4734        # Databricks transforms it back to the colon/dot notation
4735        if json_path:
4736            this = self.expression(
4737                exp.JSONExtract,
4738                this=this,
4739                expression=self.dialect.to_json_path(exp.Literal.string(".".join(json_path))),
4740                variant_extract=True,
4741            )
4742
4743            while casts:
4744                this = self.expression(exp.Cast, this=this, to=casts.pop())
4745
4746        return this
4747
4748    def _parse_dcolon(self) -> t.Optional[exp.Expression]:
4749        return self._parse_types()
4750
4751    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4752        this = self._parse_bracket(this)
4753
4754        while self._match_set(self.COLUMN_OPERATORS):
4755            op_token = self._prev.token_type
4756            op = self.COLUMN_OPERATORS.get(op_token)
4757
4758            if op_token == TokenType.DCOLON:
4759                field = self._parse_dcolon()
4760                if not field:
4761                    self.raise_error("Expected type")
4762            elif op and self._curr:
4763                field = self._parse_column_reference()
4764            else:
4765                field = self._parse_field(any_token=True, anonymous_func=True)
4766
4767            if isinstance(field, exp.Func) and this:
4768                # bigquery allows function calls like x.y.count(...)
4769                # SAFE.SUBSTR(...)
4770                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
4771                this = exp.replace_tree(
4772                    this,
4773                    lambda n: (
4774                        self.expression(exp.Dot, this=n.args.get("table"), expression=n.this)
4775                        if n.table
4776                        else n.this
4777                    )
4778                    if isinstance(n, exp.Column)
4779                    else n,
4780                )
4781
4782            if op:
4783                this = op(self, this, field)
4784            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
4785                this = self.expression(
4786                    exp.Column,
4787                    this=field,
4788                    table=this.this,
4789                    db=this.args.get("table"),
4790                    catalog=this.args.get("db"),
4791                )
4792            else:
4793                this = self.expression(exp.Dot, this=this, expression=field)
4794
4795            this = self._parse_bracket(this)
4796
4797        return self._parse_colon_as_variant_extract(this) if self.COLON_IS_VARIANT_EXTRACT else this
4798
4799    def _parse_primary(self) -> t.Optional[exp.Expression]:
4800        if self._match_set(self.PRIMARY_PARSERS):
4801            token_type = self._prev.token_type
4802            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
4803
4804            if token_type == TokenType.STRING:
4805                expressions = [primary]
4806                while self._match(TokenType.STRING):
4807                    expressions.append(exp.Literal.string(self._prev.text))
4808
4809                if len(expressions) > 1:
4810                    return self.expression(exp.Concat, expressions=expressions)
4811
4812            return primary
4813
4814        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
4815            return exp.Literal.number(f"0.{self._prev.text}")
4816
4817        if self._match(TokenType.L_PAREN):
4818            comments = self._prev_comments
4819            query = self._parse_select()
4820
4821            if query:
4822                expressions = [query]
4823            else:
4824                expressions = self._parse_expressions()
4825
4826            this = self._parse_query_modifiers(seq_get(expressions, 0))
4827
4828            if not this and self._match(TokenType.R_PAREN, advance=False):
4829                this = self.expression(exp.Tuple)
4830            elif isinstance(this, exp.UNWRAPPED_QUERIES):
4831                this = self._parse_subquery(this=this, parse_alias=False)
4832            elif isinstance(this, exp.Subquery):
4833                this = self._parse_subquery(
4834                    this=self._parse_set_operations(this), parse_alias=False
4835                )
4836            elif len(expressions) > 1 or self._prev.token_type == TokenType.COMMA:
4837                this = self.expression(exp.Tuple, expressions=expressions)
4838            else:
4839                this = self.expression(exp.Paren, this=this)
4840
4841            if this:
4842                this.add_comments(comments)
4843
4844            self._match_r_paren(expression=this)
4845            return this
4846
4847        return None
4848
4849    def _parse_field(
4850        self,
4851        any_token: bool = False,
4852        tokens: t.Optional[t.Collection[TokenType]] = None,
4853        anonymous_func: bool = False,
4854    ) -> t.Optional[exp.Expression]:
4855        if anonymous_func:
4856            field = (
4857                self._parse_function(anonymous=anonymous_func, any_token=any_token)
4858                or self._parse_primary()
4859            )
4860        else:
4861            field = self._parse_primary() or self._parse_function(
4862                anonymous=anonymous_func, any_token=any_token
4863            )
4864        return field or self._parse_id_var(any_token=any_token, tokens=tokens)
4865
4866    def _parse_function(
4867        self,
4868        functions: t.Optional[t.Dict[str, t.Callable]] = None,
4869        anonymous: bool = False,
4870        optional_parens: bool = True,
4871        any_token: bool = False,
4872    ) -> t.Optional[exp.Expression]:
4873        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
4874        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
4875        fn_syntax = False
4876        if (
4877            self._match(TokenType.L_BRACE, advance=False)
4878            and self._next
4879            and self._next.text.upper() == "FN"
4880        ):
4881            self._advance(2)
4882            fn_syntax = True
4883
4884        func = self._parse_function_call(
4885            functions=functions,
4886            anonymous=anonymous,
4887            optional_parens=optional_parens,
4888            any_token=any_token,
4889        )
4890
4891        if fn_syntax:
4892            self._match(TokenType.R_BRACE)
4893
4894        return func
4895
4896    def _parse_function_call(
4897        self,
4898        functions: t.Optional[t.Dict[str, t.Callable]] = None,
4899        anonymous: bool = False,
4900        optional_parens: bool = True,
4901        any_token: bool = False,
4902    ) -> t.Optional[exp.Expression]:
4903        if not self._curr:
4904            return None
4905
4906        comments = self._curr.comments
4907        token_type = self._curr.token_type
4908        this = self._curr.text
4909        upper = this.upper()
4910
4911        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
4912        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
4913            self._advance()
4914            return self._parse_window(parser(self))
4915
4916        if not self._next or self._next.token_type != TokenType.L_PAREN:
4917            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
4918                self._advance()
4919                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
4920
4921            return None
4922
4923        if any_token:
4924            if token_type in self.RESERVED_TOKENS:
4925                return None
4926        elif token_type not in self.FUNC_TOKENS:
4927            return None
4928
4929        self._advance(2)
4930
4931        parser = self.FUNCTION_PARSERS.get(upper)
4932        if parser and not anonymous:
4933            this = parser(self)
4934        else:
4935            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
4936
4937            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
4938                this = self.expression(subquery_predicate, this=self._parse_select())
4939                self._match_r_paren()
4940                return this
4941
4942            if functions is None:
4943                functions = self.FUNCTIONS
4944
4945            function = functions.get(upper)
4946
4947            alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS
4948            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
4949
4950            if alias:
4951                args = self._kv_to_prop_eq(args)
4952
4953            if function and not anonymous:
4954                if "dialect" in function.__code__.co_varnames:
4955                    func = function(args, dialect=self.dialect)
4956                else:
4957                    func = function(args)
4958
4959                func = self.validate_expression(func, args)
4960                if not self.dialect.NORMALIZE_FUNCTIONS:
4961                    func.meta["name"] = this
4962
4963                this = func
4964            else:
4965                if token_type == TokenType.IDENTIFIER:
4966                    this = exp.Identifier(this=this, quoted=True)
4967                this = self.expression(exp.Anonymous, this=this, expressions=args)
4968
4969        if isinstance(this, exp.Expression):
4970            this.add_comments(comments)
4971
4972        self._match_r_paren(this)
4973        return self._parse_window(this)
4974
4975    def _kv_to_prop_eq(self, expressions: t.List[exp.Expression]) -> t.List[exp.Expression]:
4976        transformed = []
4977
4978        for e in expressions:
4979            if isinstance(e, self.KEY_VALUE_DEFINITIONS):
4980                if isinstance(e, exp.Alias):
4981                    e = self.expression(exp.PropertyEQ, this=e.args.get("alias"), expression=e.this)
4982
4983                if not isinstance(e, exp.PropertyEQ):
4984                    e = self.expression(
4985                        exp.PropertyEQ, this=exp.to_identifier(e.this.name), expression=e.expression
4986                    )
4987
4988                if isinstance(e.this, exp.Column):
4989                    e.this.replace(e.this.this)
4990
4991            transformed.append(e)
4992
4993        return transformed
4994
4995    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
4996        return self._parse_column_def(self._parse_id_var())
4997
4998    def _parse_user_defined_function(
4999        self, kind: t.Optional[TokenType] = None
5000    ) -> t.Optional[exp.Expression]:
5001        this = self._parse_id_var()
5002
5003        while self._match(TokenType.DOT):
5004            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
5005
5006        if not self._match(TokenType.L_PAREN):
5007            return this
5008
5009        expressions = self._parse_csv(self._parse_function_parameter)
5010        self._match_r_paren()
5011        return self.expression(
5012            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
5013        )
5014
5015    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
5016        literal = self._parse_primary()
5017        if literal:
5018            return self.expression(exp.Introducer, this=token.text, expression=literal)
5019
5020        return self.expression(exp.Identifier, this=token.text)
5021
5022    def _parse_session_parameter(self) -> exp.SessionParameter:
5023        kind = None
5024        this = self._parse_id_var() or self._parse_primary()
5025
5026        if this and self._match(TokenType.DOT):
5027            kind = this.name
5028            this = self._parse_var() or self._parse_primary()
5029
5030        return self.expression(exp.SessionParameter, this=this, kind=kind)
5031
5032    def _parse_lambda_arg(self) -> t.Optional[exp.Expression]:
5033        return self._parse_id_var()
5034
5035    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
5036        index = self._index
5037
5038        if self._match(TokenType.L_PAREN):
5039            expressions = t.cast(
5040                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_lambda_arg)
5041            )
5042
5043            if not self._match(TokenType.R_PAREN):
5044                self._retreat(index)
5045        else:
5046            expressions = [self._parse_lambda_arg()]
5047
5048        if self._match_set(self.LAMBDAS):
5049            return self.LAMBDAS[self._prev.token_type](self, expressions)
5050
5051        self._retreat(index)
5052
5053        this: t.Optional[exp.Expression]
5054
5055        if self._match(TokenType.DISTINCT):
5056            this = self.expression(
5057                exp.Distinct, expressions=self._parse_csv(self._parse_assignment)
5058            )
5059        else:
5060            this = self._parse_select_or_expression(alias=alias)
5061
5062        return self._parse_limit(
5063            self._parse_order(self._parse_having_max(self._parse_respect_or_ignore_nulls(this)))
5064        )
5065
5066    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
5067        index = self._index
5068        if not self._match(TokenType.L_PAREN):
5069            return this
5070
5071        # Disambiguate between schema and subquery/CTE, e.g. in INSERT INTO table (<expr>),
5072        # expr can be of both types
5073        if self._match_set(self.SELECT_START_TOKENS):
5074            self._retreat(index)
5075            return this
5076        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
5077        self._match_r_paren()
5078        return self.expression(exp.Schema, this=this, expressions=args)
5079
5080    def _parse_field_def(self) -> t.Optional[exp.Expression]:
5081        return self._parse_column_def(self._parse_field(any_token=True))
5082
5083    def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5084        # column defs are not really columns, they're identifiers
5085        if isinstance(this, exp.Column):
5086            this = this.this
5087
5088        kind = self._parse_types(schema=True)
5089
5090        if self._match_text_seq("FOR", "ORDINALITY"):
5091            return self.expression(exp.ColumnDef, this=this, ordinality=True)
5092
5093        constraints: t.List[exp.Expression] = []
5094
5095        if (not kind and self._match(TokenType.ALIAS)) or self._match_texts(
5096            ("ALIAS", "MATERIALIZED")
5097        ):
5098            persisted = self._prev.text.upper() == "MATERIALIZED"
5099            constraints.append(
5100                self.expression(
5101                    exp.ComputedColumnConstraint,
5102                    this=self._parse_assignment(),
5103                    persisted=persisted or self._match_text_seq("PERSISTED"),
5104                    not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
5105                )
5106            )
5107        elif kind and self._match_pair(TokenType.ALIAS, TokenType.L_PAREN, advance=False):
5108            self._match(TokenType.ALIAS)
5109            constraints.append(
5110                self.expression(exp.TransformColumnConstraint, this=self._parse_field())
5111            )
5112
5113        while True:
5114            constraint = self._parse_column_constraint()
5115            if not constraint:
5116                break
5117            constraints.append(constraint)
5118
5119        if not kind and not constraints:
5120            return this
5121
5122        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
5123
5124    def _parse_auto_increment(
5125        self,
5126    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
5127        start = None
5128        increment = None
5129
5130        if self._match(TokenType.L_PAREN, advance=False):
5131            args = self._parse_wrapped_csv(self._parse_bitwise)
5132            start = seq_get(args, 0)
5133            increment = seq_get(args, 1)
5134        elif self._match_text_seq("START"):
5135            start = self._parse_bitwise()
5136            self._match_text_seq("INCREMENT")
5137            increment = self._parse_bitwise()
5138
5139        if start and increment:
5140            return exp.GeneratedAsIdentityColumnConstraint(start=start, increment=increment)
5141
5142        return exp.AutoIncrementColumnConstraint()
5143
5144    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
5145        if not self._match_text_seq("REFRESH"):
5146            self._retreat(self._index - 1)
5147            return None
5148        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
5149
5150    def _parse_compress(self) -> exp.CompressColumnConstraint:
5151        if self._match(TokenType.L_PAREN, advance=False):
5152            return self.expression(
5153                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
5154            )
5155
5156        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
5157
5158    def _parse_generated_as_identity(
5159        self,
5160    ) -> (
5161        exp.GeneratedAsIdentityColumnConstraint
5162        | exp.ComputedColumnConstraint
5163        | exp.GeneratedAsRowColumnConstraint
5164    ):
5165        if self._match_text_seq("BY", "DEFAULT"):
5166            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
5167            this = self.expression(
5168                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
5169            )
5170        else:
5171            self._match_text_seq("ALWAYS")
5172            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
5173
5174        self._match(TokenType.ALIAS)
5175
5176        if self._match_text_seq("ROW"):
5177            start = self._match_text_seq("START")
5178            if not start:
5179                self._match(TokenType.END)
5180            hidden = self._match_text_seq("HIDDEN")
5181            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
5182
5183        identity = self._match_text_seq("IDENTITY")
5184
5185        if self._match(TokenType.L_PAREN):
5186            if self._match(TokenType.START_WITH):
5187                this.set("start", self._parse_bitwise())
5188            if self._match_text_seq("INCREMENT", "BY"):
5189                this.set("increment", self._parse_bitwise())
5190            if self._match_text_seq("MINVALUE"):
5191                this.set("minvalue", self._parse_bitwise())
5192            if self._match_text_seq("MAXVALUE"):
5193                this.set("maxvalue", self._parse_bitwise())
5194
5195            if self._match_text_seq("CYCLE"):
5196                this.set("cycle", True)
5197            elif self._match_text_seq("NO", "CYCLE"):
5198                this.set("cycle", False)
5199
5200            if not identity:
5201                this.set("expression", self._parse_range())
5202            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
5203                args = self._parse_csv(self._parse_bitwise)
5204                this.set("start", seq_get(args, 0))
5205                this.set("increment", seq_get(args, 1))
5206
5207            self._match_r_paren()
5208
5209        return this
5210
5211    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
5212        self._match_text_seq("LENGTH")
5213        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
5214
5215    def _parse_not_constraint(self) -> t.Optional[exp.Expression]:
5216        if self._match_text_seq("NULL"):
5217            return self.expression(exp.NotNullColumnConstraint)
5218        if self._match_text_seq("CASESPECIFIC"):
5219            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
5220        if self._match_text_seq("FOR", "REPLICATION"):
5221            return self.expression(exp.NotForReplicationColumnConstraint)
5222        return None
5223
5224    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
5225        if self._match(TokenType.CONSTRAINT):
5226            this = self._parse_id_var()
5227        else:
5228            this = None
5229
5230        if self._match_texts(self.CONSTRAINT_PARSERS):
5231            return self.expression(
5232                exp.ColumnConstraint,
5233                this=this,
5234                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
5235            )
5236
5237        return this
5238
5239    def _parse_constraint(self) -> t.Optional[exp.Expression]:
5240        if not self._match(TokenType.CONSTRAINT):
5241            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
5242
5243        return self.expression(
5244            exp.Constraint,
5245            this=self._parse_id_var(),
5246            expressions=self._parse_unnamed_constraints(),
5247        )
5248
5249    def _parse_unnamed_constraints(self) -> t.List[exp.Expression]:
5250        constraints = []
5251        while True:
5252            constraint = self._parse_unnamed_constraint() or self._parse_function()
5253            if not constraint:
5254                break
5255            constraints.append(constraint)
5256
5257        return constraints
5258
5259    def _parse_unnamed_constraint(
5260        self, constraints: t.Optional[t.Collection[str]] = None
5261    ) -> t.Optional[exp.Expression]:
5262        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
5263            constraints or self.CONSTRAINT_PARSERS
5264        ):
5265            return None
5266
5267        constraint = self._prev.text.upper()
5268        if constraint not in self.CONSTRAINT_PARSERS:
5269            self.raise_error(f"No parser found for schema constraint {constraint}.")
5270
5271        return self.CONSTRAINT_PARSERS[constraint](self)
5272
5273    def _parse_unique_key(self) -> t.Optional[exp.Expression]:
5274        return self._parse_id_var(any_token=False)
5275
5276    def _parse_unique(self) -> exp.UniqueColumnConstraint:
5277        self._match_text_seq("KEY")
5278        return self.expression(
5279            exp.UniqueColumnConstraint,
5280            nulls=self._match_text_seq("NULLS", "NOT", "DISTINCT"),
5281            this=self._parse_schema(self._parse_unique_key()),
5282            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
5283            on_conflict=self._parse_on_conflict(),
5284        )
5285
5286    def _parse_key_constraint_options(self) -> t.List[str]:
5287        options = []
5288        while True:
5289            if not self._curr:
5290                break
5291
5292            if self._match(TokenType.ON):
5293                action = None
5294                on = self._advance_any() and self._prev.text
5295
5296                if self._match_text_seq("NO", "ACTION"):
5297                    action = "NO ACTION"
5298                elif self._match_text_seq("CASCADE"):
5299                    action = "CASCADE"
5300                elif self._match_text_seq("RESTRICT"):
5301                    action = "RESTRICT"
5302                elif self._match_pair(TokenType.SET, TokenType.NULL):
5303                    action = "SET NULL"
5304                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
5305                    action = "SET DEFAULT"
5306                else:
5307                    self.raise_error("Invalid key constraint")
5308
5309                options.append(f"ON {on} {action}")
5310            else:
5311                var = self._parse_var_from_options(
5312                    self.KEY_CONSTRAINT_OPTIONS, raise_unmatched=False
5313                )
5314                if not var:
5315                    break
5316                options.append(var.name)
5317
5318        return options
5319
5320    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
5321        if match and not self._match(TokenType.REFERENCES):
5322            return None
5323
5324        expressions = None
5325        this = self._parse_table(schema=True)
5326        options = self._parse_key_constraint_options()
5327        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
5328
5329    def _parse_foreign_key(self) -> exp.ForeignKey:
5330        expressions = self._parse_wrapped_id_vars()
5331        reference = self._parse_references()
5332        options = {}
5333
5334        while self._match(TokenType.ON):
5335            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
5336                self.raise_error("Expected DELETE or UPDATE")
5337
5338            kind = self._prev.text.lower()
5339
5340            if self._match_text_seq("NO", "ACTION"):
5341                action = "NO ACTION"
5342            elif self._match(TokenType.SET):
5343                self._match_set((TokenType.NULL, TokenType.DEFAULT))
5344                action = "SET " + self._prev.text.upper()
5345            else:
5346                self._advance()
5347                action = self._prev.text.upper()
5348
5349            options[kind] = action
5350
5351        return self.expression(
5352            exp.ForeignKey,
5353            expressions=expressions,
5354            reference=reference,
5355            **options,  # type: ignore
5356        )
5357
5358    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
5359        return self._parse_field()
5360
5361    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
5362        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
5363            self._retreat(self._index - 1)
5364            return None
5365
5366        id_vars = self._parse_wrapped_id_vars()
5367        return self.expression(
5368            exp.PeriodForSystemTimeConstraint,
5369            this=seq_get(id_vars, 0),
5370            expression=seq_get(id_vars, 1),
5371        )
5372
5373    def _parse_primary_key(
5374        self, wrapped_optional: bool = False, in_props: bool = False
5375    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
5376        desc = (
5377            self._match_set((TokenType.ASC, TokenType.DESC))
5378            and self._prev.token_type == TokenType.DESC
5379        )
5380
5381        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
5382            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
5383
5384        expressions = self._parse_wrapped_csv(
5385            self._parse_primary_key_part, optional=wrapped_optional
5386        )
5387        options = self._parse_key_constraint_options()
5388        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
5389
5390    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
5391        return self._parse_slice(self._parse_alias(self._parse_assignment(), explicit=True))
5392
5393    def _parse_bracket(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
5394        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
5395            return this
5396
5397        bracket_kind = self._prev.token_type
5398        expressions = self._parse_csv(
5399            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
5400        )
5401
5402        if bracket_kind == TokenType.L_BRACKET and not self._match(TokenType.R_BRACKET):
5403            self.raise_error("Expected ]")
5404        elif bracket_kind == TokenType.L_BRACE and not self._match(TokenType.R_BRACE):
5405            self.raise_error("Expected }")
5406
5407        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
5408        if bracket_kind == TokenType.L_BRACE:
5409            this = self.expression(exp.Struct, expressions=self._kv_to_prop_eq(expressions))
5410        elif not this:
5411            this = self.expression(exp.Array, expressions=expressions)
5412        else:
5413            constructor_type = self.ARRAY_CONSTRUCTORS.get(this.name.upper())
5414            if constructor_type:
5415                return self.expression(constructor_type, expressions=expressions)
5416
5417            expressions = apply_index_offset(this, expressions, -self.dialect.INDEX_OFFSET)
5418            this = self.expression(exp.Bracket, this=this, expressions=expressions)
5419
5420        self._add_comments(this)
5421        return self._parse_bracket(this)
5422
5423    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5424        if self._match(TokenType.COLON):
5425            return self.expression(exp.Slice, this=this, expression=self._parse_assignment())
5426        return this
5427
5428    def _parse_case(self) -> t.Optional[exp.Expression]:
5429        ifs = []
5430        default = None
5431
5432        comments = self._prev_comments
5433        expression = self._parse_assignment()
5434
5435        while self._match(TokenType.WHEN):
5436            this = self._parse_assignment()
5437            self._match(TokenType.THEN)
5438            then = self._parse_assignment()
5439            ifs.append(self.expression(exp.If, this=this, true=then))
5440
5441        if self._match(TokenType.ELSE):
5442            default = self._parse_assignment()
5443
5444        if not self._match(TokenType.END):
5445            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
5446                default = exp.column("interval")
5447            else:
5448                self.raise_error("Expected END after CASE", self._prev)
5449
5450        return self.expression(
5451            exp.Case, comments=comments, this=expression, ifs=ifs, default=default
5452        )
5453
5454    def _parse_if(self) -> t.Optional[exp.Expression]:
5455        if self._match(TokenType.L_PAREN):
5456            args = self._parse_csv(self._parse_assignment)
5457            this = self.validate_expression(exp.If.from_arg_list(args), args)
5458            self._match_r_paren()
5459        else:
5460            index = self._index - 1
5461
5462            if self.NO_PAREN_IF_COMMANDS and index == 0:
5463                return self._parse_as_command(self._prev)
5464
5465            condition = self._parse_assignment()
5466
5467            if not condition:
5468                self._retreat(index)
5469                return None
5470
5471            self._match(TokenType.THEN)
5472            true = self._parse_assignment()
5473            false = self._parse_assignment() if self._match(TokenType.ELSE) else None
5474            self._match(TokenType.END)
5475            this = self.expression(exp.If, this=condition, true=true, false=false)
5476
5477        return this
5478
5479    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
5480        if not self._match_text_seq("VALUE", "FOR"):
5481            self._retreat(self._index - 1)
5482            return None
5483
5484        return self.expression(
5485            exp.NextValueFor,
5486            this=self._parse_column(),
5487            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
5488        )
5489
5490    def _parse_extract(self) -> exp.Extract | exp.Anonymous:
5491        this = self._parse_function() or self._parse_var_or_string(upper=True)
5492
5493        if self._match(TokenType.FROM):
5494            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
5495
5496        if not self._match(TokenType.COMMA):
5497            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
5498
5499        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
5500
5501    def _parse_gap_fill(self) -> exp.GapFill:
5502        self._match(TokenType.TABLE)
5503        this = self._parse_table()
5504
5505        self._match(TokenType.COMMA)
5506        args = [this, *self._parse_csv(self._parse_lambda)]
5507
5508        gap_fill = exp.GapFill.from_arg_list(args)
5509        return self.validate_expression(gap_fill, args)
5510
5511    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
5512        this = self._parse_assignment()
5513
5514        if not self._match(TokenType.ALIAS):
5515            if self._match(TokenType.COMMA):
5516                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
5517
5518            self.raise_error("Expected AS after CAST")
5519
5520        fmt = None
5521        to = self._parse_types()
5522
5523        if self._match(TokenType.FORMAT):
5524            fmt_string = self._parse_string()
5525            fmt = self._parse_at_time_zone(fmt_string)
5526
5527            if not to:
5528                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
5529            if to.this in exp.DataType.TEMPORAL_TYPES:
5530                this = self.expression(
5531                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
5532                    this=this,
5533                    format=exp.Literal.string(
5534                        format_time(
5535                            fmt_string.this if fmt_string else "",
5536                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
5537                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
5538                        )
5539                    ),
5540                    safe=safe,
5541                )
5542
5543                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
5544                    this.set("zone", fmt.args["zone"])
5545                return this
5546        elif not to:
5547            self.raise_error("Expected TYPE after CAST")
5548        elif isinstance(to, exp.Identifier):
5549            to = exp.DataType.build(to.name, udt=True)
5550        elif to.this == exp.DataType.Type.CHAR:
5551            if self._match(TokenType.CHARACTER_SET):
5552                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
5553
5554        return self.expression(
5555            exp.Cast if strict else exp.TryCast,
5556            this=this,
5557            to=to,
5558            format=fmt,
5559            safe=safe,
5560            action=self._parse_var_from_options(self.CAST_ACTIONS, raise_unmatched=False),
5561        )
5562
5563    def _parse_string_agg(self) -> exp.Expression:
5564        if self._match(TokenType.DISTINCT):
5565            args: t.List[t.Optional[exp.Expression]] = [
5566                self.expression(exp.Distinct, expressions=[self._parse_assignment()])
5567            ]
5568            if self._match(TokenType.COMMA):
5569                args.extend(self._parse_csv(self._parse_assignment))
5570        else:
5571            args = self._parse_csv(self._parse_assignment)  # type: ignore
5572
5573        index = self._index
5574        if not self._match(TokenType.R_PAREN) and args:
5575            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
5576            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
5577            args[-1] = self._parse_limit(this=self._parse_order(this=args[-1]))
5578            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
5579
5580        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
5581        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
5582        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
5583        if not self._match_text_seq("WITHIN", "GROUP"):
5584            self._retreat(index)
5585            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
5586
5587        self._match_l_paren()  # The corresponding match_r_paren will be called in parse_function (caller)
5588        order = self._parse_order(this=seq_get(args, 0))
5589        return self.expression(exp.GroupConcat, this=order, separator=seq_get(args, 1))
5590
5591    def _parse_convert(
5592        self, strict: bool, safe: t.Optional[bool] = None
5593    ) -> t.Optional[exp.Expression]:
5594        this = self._parse_bitwise()
5595
5596        if self._match(TokenType.USING):
5597            to: t.Optional[exp.Expression] = self.expression(
5598                exp.CharacterSet, this=self._parse_var()
5599            )
5600        elif self._match(TokenType.COMMA):
5601            to = self._parse_types()
5602        else:
5603            to = None
5604
5605        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
5606
5607    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
5608        """
5609        There are generally two variants of the DECODE function:
5610
5611        - DECODE(bin, charset)
5612        - DECODE(expression, search, result [, search, result] ... [, default])
5613
5614        The second variant will always be parsed into a CASE expression. Note that NULL
5615        needs special treatment, since we need to explicitly check for it with `IS NULL`,
5616        instead of relying on pattern matching.
5617        """
5618        args = self._parse_csv(self._parse_assignment)
5619
5620        if len(args) < 3:
5621            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
5622
5623        expression, *expressions = args
5624        if not expression:
5625            return None
5626
5627        ifs = []
5628        for search, result in zip(expressions[::2], expressions[1::2]):
5629            if not search or not result:
5630                return None
5631
5632            if isinstance(search, exp.Literal):
5633                ifs.append(
5634                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
5635                )
5636            elif isinstance(search, exp.Null):
5637                ifs.append(
5638                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
5639                )
5640            else:
5641                cond = exp.or_(
5642                    exp.EQ(this=expression.copy(), expression=search),
5643                    exp.and_(
5644                        exp.Is(this=expression.copy(), expression=exp.Null()),
5645                        exp.Is(this=search.copy(), expression=exp.Null()),
5646                        copy=False,
5647                    ),
5648                    copy=False,
5649                )
5650                ifs.append(exp.If(this=cond, true=result))
5651
5652        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
5653
5654    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
5655        self._match_text_seq("KEY")
5656        key = self._parse_column()
5657        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
5658        self._match_text_seq("VALUE")
5659        value = self._parse_bitwise()
5660
5661        if not key and not value:
5662            return None
5663        return self.expression(exp.JSONKeyValue, this=key, expression=value)
5664
5665    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5666        if not this or not self._match_text_seq("FORMAT", "JSON"):
5667            return this
5668
5669        return self.expression(exp.FormatJson, this=this)
5670
5671    def _parse_on_handling(self, on: str, *values: str) -> t.Optional[str]:
5672        # Parses the "X ON Y" syntax, i.e. NULL ON NULL (Oracle, T-SQL)
5673        for value in values:
5674            if self._match_text_seq(value, "ON", on):
5675                return f"{value} ON {on}"
5676
5677        return None
5678
5679    @t.overload
5680    def _parse_json_object(self, agg: Lit[False]) -> exp.JSONObject: ...
5681
5682    @t.overload
5683    def _parse_json_object(self, agg: Lit[True]) -> exp.JSONObjectAgg: ...
5684
5685    def _parse_json_object(self, agg=False):
5686        star = self._parse_star()
5687        expressions = (
5688            [star]
5689            if star
5690            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
5691        )
5692        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
5693
5694        unique_keys = None
5695        if self._match_text_seq("WITH", "UNIQUE"):
5696            unique_keys = True
5697        elif self._match_text_seq("WITHOUT", "UNIQUE"):
5698            unique_keys = False
5699
5700        self._match_text_seq("KEYS")
5701
5702        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
5703            self._parse_type()
5704        )
5705        encoding = self._match_text_seq("ENCODING") and self._parse_var()
5706
5707        return self.expression(
5708            exp.JSONObjectAgg if agg else exp.JSONObject,
5709            expressions=expressions,
5710            null_handling=null_handling,
5711            unique_keys=unique_keys,
5712            return_type=return_type,
5713            encoding=encoding,
5714        )
5715
5716    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
5717    def _parse_json_column_def(self) -> exp.JSONColumnDef:
5718        if not self._match_text_seq("NESTED"):
5719            this = self._parse_id_var()
5720            kind = self._parse_types(allow_identifiers=False)
5721            nested = None
5722        else:
5723            this = None
5724            kind = None
5725            nested = True
5726
5727        path = self._match_text_seq("PATH") and self._parse_string()
5728        nested_schema = nested and self._parse_json_schema()
5729
5730        return self.expression(
5731            exp.JSONColumnDef,
5732            this=this,
5733            kind=kind,
5734            path=path,
5735            nested_schema=nested_schema,
5736        )
5737
5738    def _parse_json_schema(self) -> exp.JSONSchema:
5739        self._match_text_seq("COLUMNS")
5740        return self.expression(
5741            exp.JSONSchema,
5742            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
5743        )
5744
5745    def _parse_json_table(self) -> exp.JSONTable:
5746        this = self._parse_format_json(self._parse_bitwise())
5747        path = self._match(TokenType.COMMA) and self._parse_string()
5748        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
5749        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
5750        schema = self._parse_json_schema()
5751
5752        return exp.JSONTable(
5753            this=this,
5754            schema=schema,
5755            path=path,
5756            error_handling=error_handling,
5757            empty_handling=empty_handling,
5758        )
5759
5760    def _parse_match_against(self) -> exp.MatchAgainst:
5761        expressions = self._parse_csv(self._parse_column)
5762
5763        self._match_text_seq(")", "AGAINST", "(")
5764
5765        this = self._parse_string()
5766
5767        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
5768            modifier = "IN NATURAL LANGUAGE MODE"
5769            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
5770                modifier = f"{modifier} WITH QUERY EXPANSION"
5771        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
5772            modifier = "IN BOOLEAN MODE"
5773        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
5774            modifier = "WITH QUERY EXPANSION"
5775        else:
5776            modifier = None
5777
5778        return self.expression(
5779            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
5780        )
5781
5782    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
5783    def _parse_open_json(self) -> exp.OpenJSON:
5784        this = self._parse_bitwise()
5785        path = self._match(TokenType.COMMA) and self._parse_string()
5786
5787        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
5788            this = self._parse_field(any_token=True)
5789            kind = self._parse_types()
5790            path = self._parse_string()
5791            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
5792
5793            return self.expression(
5794                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
5795            )
5796
5797        expressions = None
5798        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
5799            self._match_l_paren()
5800            expressions = self._parse_csv(_parse_open_json_column_def)
5801
5802        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
5803
5804    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
5805        args = self._parse_csv(self._parse_bitwise)
5806
5807        if self._match(TokenType.IN):
5808            return self.expression(
5809                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
5810            )
5811
5812        if haystack_first:
5813            haystack = seq_get(args, 0)
5814            needle = seq_get(args, 1)
5815        else:
5816            needle = seq_get(args, 0)
5817            haystack = seq_get(args, 1)
5818
5819        return self.expression(
5820            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
5821        )
5822
5823    def _parse_predict(self) -> exp.Predict:
5824        self._match_text_seq("MODEL")
5825        this = self._parse_table()
5826
5827        self._match(TokenType.COMMA)
5828        self._match_text_seq("TABLE")
5829
5830        return self.expression(
5831            exp.Predict,
5832            this=this,
5833            expression=self._parse_table(),
5834            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
5835        )
5836
5837    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
5838        args = self._parse_csv(self._parse_table)
5839        return exp.JoinHint(this=func_name.upper(), expressions=args)
5840
5841    def _parse_substring(self) -> exp.Substring:
5842        # Postgres supports the form: substring(string [from int] [for int])
5843        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
5844
5845        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
5846
5847        if self._match(TokenType.FROM):
5848            args.append(self._parse_bitwise())
5849        if self._match(TokenType.FOR):
5850            if len(args) == 1:
5851                args.append(exp.Literal.number(1))
5852            args.append(self._parse_bitwise())
5853
5854        return self.validate_expression(exp.Substring.from_arg_list(args), args)
5855
5856    def _parse_trim(self) -> exp.Trim:
5857        # https://www.w3resource.com/sql/character-functions/trim.php
5858        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
5859
5860        position = None
5861        collation = None
5862        expression = None
5863
5864        if self._match_texts(self.TRIM_TYPES):
5865            position = self._prev.text.upper()
5866
5867        this = self._parse_bitwise()
5868        if self._match_set((TokenType.FROM, TokenType.COMMA)):
5869            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
5870            expression = self._parse_bitwise()
5871
5872            if invert_order:
5873                this, expression = expression, this
5874
5875        if self._match(TokenType.COLLATE):
5876            collation = self._parse_bitwise()
5877
5878        return self.expression(
5879            exp.Trim, this=this, position=position, expression=expression, collation=collation
5880        )
5881
5882    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
5883        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
5884
5885    def _parse_named_window(self) -> t.Optional[exp.Expression]:
5886        return self._parse_window(self._parse_id_var(), alias=True)
5887
5888    def _parse_respect_or_ignore_nulls(
5889        self, this: t.Optional[exp.Expression]
5890    ) -> t.Optional[exp.Expression]:
5891        if self._match_text_seq("IGNORE", "NULLS"):
5892            return self.expression(exp.IgnoreNulls, this=this)
5893        if self._match_text_seq("RESPECT", "NULLS"):
5894            return self.expression(exp.RespectNulls, this=this)
5895        return this
5896
5897    def _parse_having_max(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
5898        if self._match(TokenType.HAVING):
5899            self._match_texts(("MAX", "MIN"))
5900            max = self._prev.text.upper() != "MIN"
5901            return self.expression(
5902                exp.HavingMax, this=this, expression=self._parse_column(), max=max
5903            )
5904
5905        return this
5906
5907    def _parse_window(
5908        self, this: t.Optional[exp.Expression], alias: bool = False
5909    ) -> t.Optional[exp.Expression]:
5910        func = this
5911        comments = func.comments if isinstance(func, exp.Expression) else None
5912
5913        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
5914            self._match(TokenType.WHERE)
5915            this = self.expression(
5916                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
5917            )
5918            self._match_r_paren()
5919
5920        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
5921        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
5922        if self._match_text_seq("WITHIN", "GROUP"):
5923            order = self._parse_wrapped(self._parse_order)
5924            this = self.expression(exp.WithinGroup, this=this, expression=order)
5925
5926        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
5927        # Some dialects choose to implement and some do not.
5928        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
5929
5930        # There is some code above in _parse_lambda that handles
5931        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
5932
5933        # The below changes handle
5934        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
5935
5936        # Oracle allows both formats
5937        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
5938        #   and Snowflake chose to do the same for familiarity
5939        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
5940        if isinstance(this, exp.AggFunc):
5941            ignore_respect = this.find(exp.IgnoreNulls, exp.RespectNulls)
5942
5943            if ignore_respect and ignore_respect is not this:
5944                ignore_respect.replace(ignore_respect.this)
5945                this = self.expression(ignore_respect.__class__, this=this)
5946
5947        this = self._parse_respect_or_ignore_nulls(this)
5948
5949        # bigquery select from window x AS (partition by ...)
5950        if alias:
5951            over = None
5952            self._match(TokenType.ALIAS)
5953        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
5954            return this
5955        else:
5956            over = self._prev.text.upper()
5957
5958        if comments and isinstance(func, exp.Expression):
5959            func.pop_comments()
5960
5961        if not self._match(TokenType.L_PAREN):
5962            return self.expression(
5963                exp.Window,
5964                comments=comments,
5965                this=this,
5966                alias=self._parse_id_var(False),
5967                over=over,
5968            )
5969
5970        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
5971
5972        first = self._match(TokenType.FIRST)
5973        if self._match_text_seq("LAST"):
5974            first = False
5975
5976        partition, order = self._parse_partition_and_order()
5977        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
5978
5979        if kind:
5980            self._match(TokenType.BETWEEN)
5981            start = self._parse_window_spec()
5982            self._match(TokenType.AND)
5983            end = self._parse_window_spec()
5984
5985            spec = self.expression(
5986                exp.WindowSpec,
5987                kind=kind,
5988                start=start["value"],
5989                start_side=start["side"],
5990                end=end["value"],
5991                end_side=end["side"],
5992            )
5993        else:
5994            spec = None
5995
5996        self._match_r_paren()
5997
5998        window = self.expression(
5999            exp.Window,
6000            comments=comments,
6001            this=this,
6002            partition_by=partition,
6003            order=order,
6004            spec=spec,
6005            alias=window_alias,
6006            over=over,
6007            first=first,
6008        )
6009
6010        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
6011        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
6012            return self._parse_window(window, alias=alias)
6013
6014        return window
6015
6016    def _parse_partition_and_order(
6017        self,
6018    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
6019        return self._parse_partition_by(), self._parse_order()
6020
6021    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
6022        self._match(TokenType.BETWEEN)
6023
6024        return {
6025            "value": (
6026                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
6027                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
6028                or self._parse_bitwise()
6029            ),
6030            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
6031        }
6032
6033    def _parse_alias(
6034        self, this: t.Optional[exp.Expression], explicit: bool = False
6035    ) -> t.Optional[exp.Expression]:
6036        any_token = self._match(TokenType.ALIAS)
6037        comments = self._prev_comments or []
6038
6039        if explicit and not any_token:
6040            return this
6041
6042        if self._match(TokenType.L_PAREN):
6043            aliases = self.expression(
6044                exp.Aliases,
6045                comments=comments,
6046                this=this,
6047                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
6048            )
6049            self._match_r_paren(aliases)
6050            return aliases
6051
6052        alias = self._parse_id_var(any_token, tokens=self.ALIAS_TOKENS) or (
6053            self.STRING_ALIASES and self._parse_string_as_identifier()
6054        )
6055
6056        if alias:
6057            comments.extend(alias.pop_comments())
6058            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
6059            column = this.this
6060
6061            # Moves the comment next to the alias in `expr /* comment */ AS alias`
6062            if not this.comments and column and column.comments:
6063                this.comments = column.pop_comments()
6064
6065        return this
6066
6067    def _parse_id_var(
6068        self,
6069        any_token: bool = True,
6070        tokens: t.Optional[t.Collection[TokenType]] = None,
6071    ) -> t.Optional[exp.Expression]:
6072        expression = self._parse_identifier()
6073        if not expression and (
6074            (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS)
6075        ):
6076            quoted = self._prev.token_type == TokenType.STRING
6077            expression = self.expression(exp.Identifier, this=self._prev.text, quoted=quoted)
6078
6079        return expression
6080
6081    def _parse_string(self) -> t.Optional[exp.Expression]:
6082        if self._match_set(self.STRING_PARSERS):
6083            return self.STRING_PARSERS[self._prev.token_type](self, self._prev)
6084        return self._parse_placeholder()
6085
6086    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
6087        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
6088
6089    def _parse_number(self) -> t.Optional[exp.Expression]:
6090        if self._match_set(self.NUMERIC_PARSERS):
6091            return self.NUMERIC_PARSERS[self._prev.token_type](self, self._prev)
6092        return self._parse_placeholder()
6093
6094    def _parse_identifier(self) -> t.Optional[exp.Expression]:
6095        if self._match(TokenType.IDENTIFIER):
6096            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
6097        return self._parse_placeholder()
6098
6099    def _parse_var(
6100        self,
6101        any_token: bool = False,
6102        tokens: t.Optional[t.Collection[TokenType]] = None,
6103        upper: bool = False,
6104    ) -> t.Optional[exp.Expression]:
6105        if (
6106            (any_token and self._advance_any())
6107            or self._match(TokenType.VAR)
6108            or (self._match_set(tokens) if tokens else False)
6109        ):
6110            return self.expression(
6111                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
6112            )
6113        return self._parse_placeholder()
6114
6115    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
6116        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
6117            self._advance()
6118            return self._prev
6119        return None
6120
6121    def _parse_var_or_string(self, upper: bool = False) -> t.Optional[exp.Expression]:
6122        return self._parse_string() or self._parse_var(any_token=True, upper=upper)
6123
6124    def _parse_primary_or_var(self) -> t.Optional[exp.Expression]:
6125        return self._parse_primary() or self._parse_var(any_token=True)
6126
6127    def _parse_null(self) -> t.Optional[exp.Expression]:
6128        if self._match_set(self.NULL_TOKENS):
6129            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
6130        return self._parse_placeholder()
6131
6132    def _parse_boolean(self) -> t.Optional[exp.Expression]:
6133        if self._match(TokenType.TRUE):
6134            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
6135        if self._match(TokenType.FALSE):
6136            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
6137        return self._parse_placeholder()
6138
6139    def _parse_star(self) -> t.Optional[exp.Expression]:
6140        if self._match(TokenType.STAR):
6141            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
6142        return self._parse_placeholder()
6143
6144    def _parse_parameter(self) -> exp.Parameter:
6145        this = self._parse_identifier() or self._parse_primary_or_var()
6146        return self.expression(exp.Parameter, this=this)
6147
6148    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
6149        if self._match_set(self.PLACEHOLDER_PARSERS):
6150            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
6151            if placeholder:
6152                return placeholder
6153            self._advance(-1)
6154        return None
6155
6156    def _parse_star_op(self, *keywords: str) -> t.Optional[t.List[exp.Expression]]:
6157        if not self._match_texts(keywords):
6158            return None
6159        if self._match(TokenType.L_PAREN, advance=False):
6160            return self._parse_wrapped_csv(self._parse_expression)
6161
6162        expression = self._parse_expression()
6163        return [expression] if expression else None
6164
6165    def _parse_csv(
6166        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
6167    ) -> t.List[exp.Expression]:
6168        parse_result = parse_method()
6169        items = [parse_result] if parse_result is not None else []
6170
6171        while self._match(sep):
6172            self._add_comments(parse_result)
6173            parse_result = parse_method()
6174            if parse_result is not None:
6175                items.append(parse_result)
6176
6177        return items
6178
6179    def _parse_tokens(
6180        self, parse_method: t.Callable, expressions: t.Dict
6181    ) -> t.Optional[exp.Expression]:
6182        this = parse_method()
6183
6184        while self._match_set(expressions):
6185            this = self.expression(
6186                expressions[self._prev.token_type],
6187                this=this,
6188                comments=self._prev_comments,
6189                expression=parse_method(),
6190            )
6191
6192        return this
6193
6194    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
6195        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
6196
6197    def _parse_wrapped_csv(
6198        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
6199    ) -> t.List[exp.Expression]:
6200        return self._parse_wrapped(
6201            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
6202        )
6203
6204    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
6205        wrapped = self._match(TokenType.L_PAREN)
6206        if not wrapped and not optional:
6207            self.raise_error("Expecting (")
6208        parse_result = parse_method()
6209        if wrapped:
6210            self._match_r_paren()
6211        return parse_result
6212
6213    def _parse_expressions(self) -> t.List[exp.Expression]:
6214        return self._parse_csv(self._parse_expression)
6215
6216    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
6217        return self._parse_select() or self._parse_set_operations(
6218            self._parse_expression() if alias else self._parse_assignment()
6219        )
6220
6221    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
6222        return self._parse_query_modifiers(
6223            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
6224        )
6225
6226    def _parse_transaction(self) -> exp.Transaction | exp.Command:
6227        this = None
6228        if self._match_texts(self.TRANSACTION_KIND):
6229            this = self._prev.text
6230
6231        self._match_texts(("TRANSACTION", "WORK"))
6232
6233        modes = []
6234        while True:
6235            mode = []
6236            while self._match(TokenType.VAR):
6237                mode.append(self._prev.text)
6238
6239            if mode:
6240                modes.append(" ".join(mode))
6241            if not self._match(TokenType.COMMA):
6242                break
6243
6244        return self.expression(exp.Transaction, this=this, modes=modes)
6245
6246    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
6247        chain = None
6248        savepoint = None
6249        is_rollback = self._prev.token_type == TokenType.ROLLBACK
6250
6251        self._match_texts(("TRANSACTION", "WORK"))
6252
6253        if self._match_text_seq("TO"):
6254            self._match_text_seq("SAVEPOINT")
6255            savepoint = self._parse_id_var()
6256
6257        if self._match(TokenType.AND):
6258            chain = not self._match_text_seq("NO")
6259            self._match_text_seq("CHAIN")
6260
6261        if is_rollback:
6262            return self.expression(exp.Rollback, savepoint=savepoint)
6263
6264        return self.expression(exp.Commit, chain=chain)
6265
6266    def _parse_refresh(self) -> exp.Refresh:
6267        self._match(TokenType.TABLE)
6268        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
6269
6270    def _parse_add_column(self) -> t.Optional[exp.Expression]:
6271        if not self._match_text_seq("ADD"):
6272            return None
6273
6274        self._match(TokenType.COLUMN)
6275        exists_column = self._parse_exists(not_=True)
6276        expression = self._parse_field_def()
6277
6278        if expression:
6279            expression.set("exists", exists_column)
6280
6281            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
6282            if self._match_texts(("FIRST", "AFTER")):
6283                position = self._prev.text
6284                column_position = self.expression(
6285                    exp.ColumnPosition, this=self._parse_column(), position=position
6286                )
6287                expression.set("position", column_position)
6288
6289        return expression
6290
6291    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
6292        drop = self._match(TokenType.DROP) and self._parse_drop()
6293        if drop and not isinstance(drop, exp.Command):
6294            drop.set("kind", drop.args.get("kind", "COLUMN"))
6295        return drop
6296
6297    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
6298    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
6299        return self.expression(
6300            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
6301        )
6302
6303    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
6304        index = self._index - 1
6305
6306        if self._match_set(self.ADD_CONSTRAINT_TOKENS, advance=False):
6307            return self._parse_csv(
6308                lambda: self.expression(
6309                    exp.AddConstraint, expressions=self._parse_csv(self._parse_constraint)
6310                )
6311            )
6312
6313        self._retreat(index)
6314        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
6315            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
6316
6317        if self._match_text_seq("ADD", "COLUMNS"):
6318            schema = self._parse_schema()
6319            if schema:
6320                return [schema]
6321            return []
6322
6323        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
6324
6325    def _parse_alter_table_alter(self) -> t.Optional[exp.Expression]:
6326        if self._match_texts(self.ALTER_ALTER_PARSERS):
6327            return self.ALTER_ALTER_PARSERS[self._prev.text.upper()](self)
6328
6329        # Many dialects support the ALTER [COLUMN] syntax, so if there is no
6330        # keyword after ALTER we default to parsing this statement
6331        self._match(TokenType.COLUMN)
6332        column = self._parse_field(any_token=True)
6333
6334        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
6335            return self.expression(exp.AlterColumn, this=column, drop=True)
6336        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
6337            return self.expression(exp.AlterColumn, this=column, default=self._parse_assignment())
6338        if self._match(TokenType.COMMENT):
6339            return self.expression(exp.AlterColumn, this=column, comment=self._parse_string())
6340        if self._match_text_seq("DROP", "NOT", "NULL"):
6341            return self.expression(
6342                exp.AlterColumn,
6343                this=column,
6344                drop=True,
6345                allow_null=True,
6346            )
6347        if self._match_text_seq("SET", "NOT", "NULL"):
6348            return self.expression(
6349                exp.AlterColumn,
6350                this=column,
6351                allow_null=False,
6352            )
6353        self._match_text_seq("SET", "DATA")
6354        self._match_text_seq("TYPE")
6355        return self.expression(
6356            exp.AlterColumn,
6357            this=column,
6358            dtype=self._parse_types(),
6359            collate=self._match(TokenType.COLLATE) and self._parse_term(),
6360            using=self._match(TokenType.USING) and self._parse_assignment(),
6361        )
6362
6363    def _parse_alter_diststyle(self) -> exp.AlterDistStyle:
6364        if self._match_texts(("ALL", "EVEN", "AUTO")):
6365            return self.expression(exp.AlterDistStyle, this=exp.var(self._prev.text.upper()))
6366
6367        self._match_text_seq("KEY", "DISTKEY")
6368        return self.expression(exp.AlterDistStyle, this=self._parse_column())
6369
6370    def _parse_alter_sortkey(self, compound: t.Optional[bool] = None) -> exp.AlterSortKey:
6371        if compound:
6372            self._match_text_seq("SORTKEY")
6373
6374        if self._match(TokenType.L_PAREN, advance=False):
6375            return self.expression(
6376                exp.AlterSortKey, expressions=self._parse_wrapped_id_vars(), compound=compound
6377            )
6378
6379        self._match_texts(("AUTO", "NONE"))
6380        return self.expression(
6381            exp.AlterSortKey, this=exp.var(self._prev.text.upper()), compound=compound
6382        )
6383
6384    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
6385        index = self._index - 1
6386
6387        partition_exists = self._parse_exists()
6388        if self._match(TokenType.PARTITION, advance=False):
6389            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
6390
6391        self._retreat(index)
6392        return self._parse_csv(self._parse_drop_column)
6393
6394    def _parse_alter_table_rename(self) -> t.Optional[exp.RenameTable | exp.RenameColumn]:
6395        if self._match(TokenType.COLUMN):
6396            exists = self._parse_exists()
6397            old_column = self._parse_column()
6398            to = self._match_text_seq("TO")
6399            new_column = self._parse_column()
6400
6401            if old_column is None or to is None or new_column is None:
6402                return None
6403
6404            return self.expression(exp.RenameColumn, this=old_column, to=new_column, exists=exists)
6405
6406        self._match_text_seq("TO")
6407        return self.expression(exp.RenameTable, this=self._parse_table(schema=True))
6408
6409    def _parse_alter_table_set(self) -> exp.AlterSet:
6410        alter_set = self.expression(exp.AlterSet)
6411
6412        if self._match(TokenType.L_PAREN, advance=False) or self._match_text_seq(
6413            "TABLE", "PROPERTIES"
6414        ):
6415            alter_set.set("expressions", self._parse_wrapped_csv(self._parse_assignment))
6416        elif self._match_text_seq("FILESTREAM_ON", advance=False):
6417            alter_set.set("expressions", [self._parse_assignment()])
6418        elif self._match_texts(("LOGGED", "UNLOGGED")):
6419            alter_set.set("option", exp.var(self._prev.text.upper()))
6420        elif self._match_text_seq("WITHOUT") and self._match_texts(("CLUSTER", "OIDS")):
6421            alter_set.set("option", exp.var(f"WITHOUT {self._prev.text.upper()}"))
6422        elif self._match_text_seq("LOCATION"):
6423            alter_set.set("location", self._parse_field())
6424        elif self._match_text_seq("ACCESS", "METHOD"):
6425            alter_set.set("access_method", self._parse_field())
6426        elif self._match_text_seq("TABLESPACE"):
6427            alter_set.set("tablespace", self._parse_field())
6428        elif self._match_text_seq("FILE", "FORMAT") or self._match_text_seq("FILEFORMAT"):
6429            alter_set.set("file_format", [self._parse_field()])
6430        elif self._match_text_seq("STAGE_FILE_FORMAT"):
6431            alter_set.set("file_format", self._parse_wrapped_options())
6432        elif self._match_text_seq("STAGE_COPY_OPTIONS"):
6433            alter_set.set("copy_options", self._parse_wrapped_options())
6434        elif self._match_text_seq("TAG") or self._match_text_seq("TAGS"):
6435            alter_set.set("tag", self._parse_csv(self._parse_assignment))
6436        else:
6437            if self._match_text_seq("SERDE"):
6438                alter_set.set("serde", self._parse_field())
6439
6440            alter_set.set("expressions", [self._parse_properties()])
6441
6442        return alter_set
6443
6444    def _parse_alter(self) -> exp.AlterTable | exp.Command:
6445        start = self._prev
6446
6447        if not self._match(TokenType.TABLE):
6448            return self._parse_as_command(start)
6449
6450        exists = self._parse_exists()
6451        only = self._match_text_seq("ONLY")
6452        this = self._parse_table(schema=True)
6453        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
6454
6455        if self._next:
6456            self._advance()
6457
6458        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
6459        if parser:
6460            actions = ensure_list(parser(self))
6461            options = self._parse_csv(self._parse_property)
6462
6463            if not self._curr and actions:
6464                return self.expression(
6465                    exp.AlterTable,
6466                    this=this,
6467                    exists=exists,
6468                    actions=actions,
6469                    only=only,
6470                    options=options,
6471                    cluster=cluster,
6472                )
6473
6474        return self._parse_as_command(start)
6475
6476    def _parse_merge(self) -> exp.Merge:
6477        self._match(TokenType.INTO)
6478        target = self._parse_table()
6479
6480        if target and self._match(TokenType.ALIAS, advance=False):
6481            target.set("alias", self._parse_table_alias())
6482
6483        self._match(TokenType.USING)
6484        using = self._parse_table()
6485
6486        self._match(TokenType.ON)
6487        on = self._parse_assignment()
6488
6489        return self.expression(
6490            exp.Merge,
6491            this=target,
6492            using=using,
6493            on=on,
6494            expressions=self._parse_when_matched(),
6495        )
6496
6497    def _parse_when_matched(self) -> t.List[exp.When]:
6498        whens = []
6499
6500        while self._match(TokenType.WHEN):
6501            matched = not self._match(TokenType.NOT)
6502            self._match_text_seq("MATCHED")
6503            source = (
6504                False
6505                if self._match_text_seq("BY", "TARGET")
6506                else self._match_text_seq("BY", "SOURCE")
6507            )
6508            condition = self._parse_assignment() if self._match(TokenType.AND) else None
6509
6510            self._match(TokenType.THEN)
6511
6512            if self._match(TokenType.INSERT):
6513                _this = self._parse_star()
6514                if _this:
6515                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=_this)
6516                else:
6517                    then = self.expression(
6518                        exp.Insert,
6519                        this=self._parse_value(),
6520                        expression=self._match_text_seq("VALUES") and self._parse_value(),
6521                    )
6522            elif self._match(TokenType.UPDATE):
6523                expressions = self._parse_star()
6524                if expressions:
6525                    then = self.expression(exp.Update, expressions=expressions)
6526                else:
6527                    then = self.expression(
6528                        exp.Update,
6529                        expressions=self._match(TokenType.SET)
6530                        and self._parse_csv(self._parse_equality),
6531                    )
6532            elif self._match(TokenType.DELETE):
6533                then = self.expression(exp.Var, this=self._prev.text)
6534            else:
6535                then = None
6536
6537            whens.append(
6538                self.expression(
6539                    exp.When,
6540                    matched=matched,
6541                    source=source,
6542                    condition=condition,
6543                    then=then,
6544                )
6545            )
6546        return whens
6547
6548    def _parse_show(self) -> t.Optional[exp.Expression]:
6549        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
6550        if parser:
6551            return parser(self)
6552        return self._parse_as_command(self._prev)
6553
6554    def _parse_set_item_assignment(
6555        self, kind: t.Optional[str] = None
6556    ) -> t.Optional[exp.Expression]:
6557        index = self._index
6558
6559        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
6560            return self._parse_set_transaction(global_=kind == "GLOBAL")
6561
6562        left = self._parse_primary() or self._parse_column()
6563        assignment_delimiter = self._match_texts(("=", "TO"))
6564
6565        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
6566            self._retreat(index)
6567            return None
6568
6569        right = self._parse_statement() or self._parse_id_var()
6570        if isinstance(right, (exp.Column, exp.Identifier)):
6571            right = exp.var(right.name)
6572
6573        this = self.expression(exp.EQ, this=left, expression=right)
6574        return self.expression(exp.SetItem, this=this, kind=kind)
6575
6576    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
6577        self._match_text_seq("TRANSACTION")
6578        characteristics = self._parse_csv(
6579            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
6580        )
6581        return self.expression(
6582            exp.SetItem,
6583            expressions=characteristics,
6584            kind="TRANSACTION",
6585            **{"global": global_},  # type: ignore
6586        )
6587
6588    def _parse_set_item(self) -> t.Optional[exp.Expression]:
6589        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
6590        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
6591
6592    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
6593        index = self._index
6594        set_ = self.expression(
6595            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
6596        )
6597
6598        if self._curr:
6599            self._retreat(index)
6600            return self._parse_as_command(self._prev)
6601
6602        return set_
6603
6604    def _parse_var_from_options(
6605        self, options: OPTIONS_TYPE, raise_unmatched: bool = True
6606    ) -> t.Optional[exp.Var]:
6607        start = self._curr
6608        if not start:
6609            return None
6610
6611        option = start.text.upper()
6612        continuations = options.get(option)
6613
6614        index = self._index
6615        self._advance()
6616        for keywords in continuations or []:
6617            if isinstance(keywords, str):
6618                keywords = (keywords,)
6619
6620            if self._match_text_seq(*keywords):
6621                option = f"{option} {' '.join(keywords)}"
6622                break
6623        else:
6624            if continuations or continuations is None:
6625                if raise_unmatched:
6626                    self.raise_error(f"Unknown option {option}")
6627
6628                self._retreat(index)
6629                return None
6630
6631        return exp.var(option)
6632
6633    def _parse_as_command(self, start: Token) -> exp.Command:
6634        while self._curr:
6635            self._advance()
6636        text = self._find_sql(start, self._prev)
6637        size = len(start.text)
6638        self._warn_unsupported()
6639        return exp.Command(this=text[:size], expression=text[size:])
6640
6641    def _parse_dict_property(self, this: str) -> exp.DictProperty:
6642        settings = []
6643
6644        self._match_l_paren()
6645        kind = self._parse_id_var()
6646
6647        if self._match(TokenType.L_PAREN):
6648            while True:
6649                key = self._parse_id_var()
6650                value = self._parse_primary()
6651
6652                if not key and value is None:
6653                    break
6654                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
6655            self._match(TokenType.R_PAREN)
6656
6657        self._match_r_paren()
6658
6659        return self.expression(
6660            exp.DictProperty,
6661            this=this,
6662            kind=kind.this if kind else None,
6663            settings=settings,
6664        )
6665
6666    def _parse_dict_range(self, this: str) -> exp.DictRange:
6667        self._match_l_paren()
6668        has_min = self._match_text_seq("MIN")
6669        if has_min:
6670            min = self._parse_var() or self._parse_primary()
6671            self._match_text_seq("MAX")
6672            max = self._parse_var() or self._parse_primary()
6673        else:
6674            max = self._parse_var() or self._parse_primary()
6675            min = exp.Literal.number(0)
6676        self._match_r_paren()
6677        return self.expression(exp.DictRange, this=this, min=min, max=max)
6678
6679    def _parse_comprehension(
6680        self, this: t.Optional[exp.Expression]
6681    ) -> t.Optional[exp.Comprehension]:
6682        index = self._index
6683        expression = self._parse_column()
6684        if not self._match(TokenType.IN):
6685            self._retreat(index - 1)
6686            return None
6687        iterator = self._parse_column()
6688        condition = self._parse_assignment() if self._match_text_seq("IF") else None
6689        return self.expression(
6690            exp.Comprehension,
6691            this=this,
6692            expression=expression,
6693            iterator=iterator,
6694            condition=condition,
6695        )
6696
6697    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
6698        if self._match(TokenType.HEREDOC_STRING):
6699            return self.expression(exp.Heredoc, this=self._prev.text)
6700
6701        if not self._match_text_seq("$"):
6702            return None
6703
6704        tags = ["$"]
6705        tag_text = None
6706
6707        if self._is_connected():
6708            self._advance()
6709            tags.append(self._prev.text.upper())
6710        else:
6711            self.raise_error("No closing $ found")
6712
6713        if tags[-1] != "$":
6714            if self._is_connected() and self._match_text_seq("$"):
6715                tag_text = tags[-1]
6716                tags.append("$")
6717            else:
6718                self.raise_error("No closing $ found")
6719
6720        heredoc_start = self._curr
6721
6722        while self._curr:
6723            if self._match_text_seq(*tags, advance=False):
6724                this = self._find_sql(heredoc_start, self._prev)
6725                self._advance(len(tags))
6726                return self.expression(exp.Heredoc, this=this, tag=tag_text)
6727
6728            self._advance()
6729
6730        self.raise_error(f"No closing {''.join(tags)} found")
6731        return None
6732
6733    def _find_parser(
6734        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
6735    ) -> t.Optional[t.Callable]:
6736        if not self._curr:
6737            return None
6738
6739        index = self._index
6740        this = []
6741        while True:
6742            # The current token might be multiple words
6743            curr = self._curr.text.upper()
6744            key = curr.split(" ")
6745            this.append(curr)
6746
6747            self._advance()
6748            result, trie = in_trie(trie, key)
6749            if result == TrieResult.FAILED:
6750                break
6751
6752            if result == TrieResult.EXISTS:
6753                subparser = parsers[" ".join(this)]
6754                return subparser
6755
6756        self._retreat(index)
6757        return None
6758
6759    def _match(self, token_type, advance=True, expression=None):
6760        if not self._curr:
6761            return None
6762
6763        if self._curr.token_type == token_type:
6764            if advance:
6765                self._advance()
6766            self._add_comments(expression)
6767            return True
6768
6769        return None
6770
6771    def _match_set(self, types, advance=True):
6772        if not self._curr:
6773            return None
6774
6775        if self._curr.token_type in types:
6776            if advance:
6777                self._advance()
6778            return True
6779
6780        return None
6781
6782    def _match_pair(self, token_type_a, token_type_b, advance=True):
6783        if not self._curr or not self._next:
6784            return None
6785
6786        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
6787            if advance:
6788                self._advance(2)
6789            return True
6790
6791        return None
6792
6793    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
6794        if not self._match(TokenType.L_PAREN, expression=expression):
6795            self.raise_error("Expecting (")
6796
6797    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
6798        if not self._match(TokenType.R_PAREN, expression=expression):
6799            self.raise_error("Expecting )")
6800
6801    def _match_texts(self, texts, advance=True):
6802        if self._curr and self._curr.text.upper() in texts:
6803            if advance:
6804                self._advance()
6805            return True
6806        return None
6807
6808    def _match_text_seq(self, *texts, advance=True):
6809        index = self._index
6810        for text in texts:
6811            if self._curr and self._curr.text.upper() == text:
6812                self._advance()
6813            else:
6814                self._retreat(index)
6815                return None
6816
6817        if not advance:
6818            self._retreat(index)
6819
6820        return True
6821
6822    def _replace_lambda(
6823        self, node: t.Optional[exp.Expression], expressions: t.List[exp.Expression]
6824    ) -> t.Optional[exp.Expression]:
6825        if not node:
6826            return node
6827
6828        lambda_types = {e.name: e.args.get("to") or False for e in expressions}
6829
6830        for column in node.find_all(exp.Column):
6831            typ = lambda_types.get(column.parts[0].name)
6832            if typ is not None:
6833                dot_or_id = column.to_dot() if column.table else column.this
6834
6835                if typ:
6836                    dot_or_id = self.expression(
6837                        exp.Cast,
6838                        this=dot_or_id,
6839                        to=typ,
6840                    )
6841
6842                parent = column.parent
6843
6844                while isinstance(parent, exp.Dot):
6845                    if not isinstance(parent.parent, exp.Dot):
6846                        parent.replace(dot_or_id)
6847                        break
6848                    parent = parent.parent
6849                else:
6850                    if column is node:
6851                        node = dot_or_id
6852                    else:
6853                        column.replace(dot_or_id)
6854        return node
6855
6856    def _parse_truncate_table(self) -> t.Optional[exp.TruncateTable] | exp.Expression:
6857        start = self._prev
6858
6859        # Not to be confused with TRUNCATE(number, decimals) function call
6860        if self._match(TokenType.L_PAREN):
6861            self._retreat(self._index - 2)
6862            return self._parse_function()
6863
6864        # Clickhouse supports TRUNCATE DATABASE as well
6865        is_database = self._match(TokenType.DATABASE)
6866
6867        self._match(TokenType.TABLE)
6868
6869        exists = self._parse_exists(not_=False)
6870
6871        expressions = self._parse_csv(
6872            lambda: self._parse_table(schema=True, is_db_reference=is_database)
6873        )
6874
6875        cluster = self._parse_on_property() if self._match(TokenType.ON) else None
6876
6877        if self._match_text_seq("RESTART", "IDENTITY"):
6878            identity = "RESTART"
6879        elif self._match_text_seq("CONTINUE", "IDENTITY"):
6880            identity = "CONTINUE"
6881        else:
6882            identity = None
6883
6884        if self._match_text_seq("CASCADE") or self._match_text_seq("RESTRICT"):
6885            option = self._prev.text
6886        else:
6887            option = None
6888
6889        partition = self._parse_partition()
6890
6891        # Fallback case
6892        if self._curr:
6893            return self._parse_as_command(start)
6894
6895        return self.expression(
6896            exp.TruncateTable,
6897            expressions=expressions,
6898            is_database=is_database,
6899            exists=exists,
6900            cluster=cluster,
6901            identity=identity,
6902            option=option,
6903            partition=partition,
6904        )
6905
6906    def _parse_with_operator(self) -> t.Optional[exp.Expression]:
6907        this = self._parse_ordered(self._parse_opclass)
6908
6909        if not self._match(TokenType.WITH):
6910            return this
6911
6912        op = self._parse_var(any_token=True)
6913
6914        return self.expression(exp.WithOperator, this=this, op=op)
6915
6916    def _parse_wrapped_options(self) -> t.List[t.Optional[exp.Expression]]:
6917        self._match(TokenType.EQ)
6918        self._match(TokenType.L_PAREN)
6919
6920        opts: t.List[t.Optional[exp.Expression]] = []
6921        while self._curr and not self._match(TokenType.R_PAREN):
6922            if self._match_text_seq("FORMAT_NAME", "="):
6923                # The FORMAT_NAME can be set to an identifier for Snowflake and T-SQL,
6924                # so we parse it separately to use _parse_field()
6925                prop = self.expression(
6926                    exp.Property, this=exp.var("FORMAT_NAME"), value=self._parse_field()
6927                )
6928                opts.append(prop)
6929            else:
6930                opts.append(self._parse_property())
6931
6932            self._match(TokenType.COMMA)
6933
6934        return opts
6935
6936    def _parse_copy_parameters(self) -> t.List[exp.CopyParameter]:
6937        sep = TokenType.COMMA if self.dialect.COPY_PARAMS_ARE_CSV else None
6938
6939        options = []
6940        while self._curr and not self._match(TokenType.R_PAREN, advance=False):
6941            option = self._parse_var(any_token=True)
6942            prev = self._prev.text.upper()
6943
6944            # Different dialects might separate options and values by white space, "=" and "AS"
6945            self._match(TokenType.EQ)
6946            self._match(TokenType.ALIAS)
6947
6948            param = self.expression(exp.CopyParameter, this=option)
6949
6950            if prev in self.COPY_INTO_VARLEN_OPTIONS and self._match(
6951                TokenType.L_PAREN, advance=False
6952            ):
6953                # Snowflake FILE_FORMAT case, Databricks COPY & FORMAT options
6954                param.set("expressions", self._parse_wrapped_options())
6955            elif prev == "FILE_FORMAT":
6956                # T-SQL's external file format case
6957                param.set("expression", self._parse_field())
6958            else:
6959                param.set("expression", self._parse_unquoted_field())
6960
6961            options.append(param)
6962            self._match(sep)
6963
6964        return options
6965
6966    def _parse_credentials(self) -> t.Optional[exp.Credentials]:
6967        expr = self.expression(exp.Credentials)
6968
6969        if self._match_text_seq("STORAGE_INTEGRATION", "="):
6970            expr.set("storage", self._parse_field())
6971        if self._match_text_seq("CREDENTIALS"):
6972            # Snowflake case: CREDENTIALS = (...), Redshift case: CREDENTIALS <string>
6973            creds = (
6974                self._parse_wrapped_options() if self._match(TokenType.EQ) else self._parse_field()
6975            )
6976            expr.set("credentials", creds)
6977        if self._match_text_seq("ENCRYPTION"):
6978            expr.set("encryption", self._parse_wrapped_options())
6979        if self._match_text_seq("IAM_ROLE"):
6980            expr.set("iam_role", self._parse_field())
6981        if self._match_text_seq("REGION"):
6982            expr.set("region", self._parse_field())
6983
6984        return expr
6985
6986    def _parse_file_location(self) -> t.Optional[exp.Expression]:
6987        return self._parse_field()
6988
6989    def _parse_copy(self) -> exp.Copy | exp.Command:
6990        start = self._prev
6991
6992        self._match(TokenType.INTO)
6993
6994        this = (
6995            self._parse_select(nested=True, parse_subquery_alias=False)
6996            if self._match(TokenType.L_PAREN, advance=False)
6997            else self._parse_table(schema=True)
6998        )
6999
7000        kind = self._match(TokenType.FROM) or not self._match_text_seq("TO")
7001
7002        files = self._parse_csv(self._parse_file_location)
7003        credentials = self._parse_credentials()
7004
7005        self._match_text_seq("WITH")
7006
7007        params = self._parse_wrapped(self._parse_copy_parameters, optional=True)
7008
7009        # Fallback case
7010        if self._curr:
7011            return self._parse_as_command(start)
7012
7013        return self.expression(
7014            exp.Copy,
7015            this=this,
7016            kind=kind,
7017            credentials=credentials,
7018            files=files,
7019            params=params,
7020        )

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)
1278    def __init__(
1279        self,
1280        error_level: t.Optional[ErrorLevel] = None,
1281        error_message_context: int = 100,
1282        max_errors: int = 3,
1283        dialect: DialectType = None,
1284    ):
1285        from sqlglot.dialects import Dialect
1286
1287        self.error_level = error_level or ErrorLevel.IMMEDIATE
1288        self.error_message_context = error_message_context
1289        self.max_errors = max_errors
1290        self.dialect = Dialect.get_or_raise(dialect)
1291        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'>>, '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': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Array'>>, 'ARRAY_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayAgg'>>, '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': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Chr'>>, 'CHAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Chr'>>, 'COALESCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'IFNULL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'NVL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Coalesce'>>, 'COLLATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Collate'>>, 'COMBINED_AGG_FUNC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedAggFunc'>>, 'COMBINED_PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.CombinedParameterizedAgg'>>, 'CONCAT': <function Parser.<lambda>>, 'CONCAT_WS': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ConnectByRoot'>>, 'CONVERT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Convert'>>, 'CORR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Corr'>>, 'COUNT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Count'>>, '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'>>, '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'>>, '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'>>, 'EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Extract'>>, 'FIRST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.First'>>, 'FIRST_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FirstValue'>>, 'FLATTEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Flatten'>>, 'FLOOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Floor'>>, 'FROM_BASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase'>>, 'FROM_BASE64': <bound method Func.from_arg_list of <class 'sqlglot.expressions.FromBase64'>>, 'GAP_FILL': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GapFill'>>, 'GENERATE_DATE_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateDateArray'>>, 'GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateSeries'>>, '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'>>, '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_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'>>, 'JSON_EXTRACT': <function build_extract_json_with_path.<locals>._builder>, 'JSON_EXTRACT_SCALAR': <function build_extract_json_with_path.<locals>._builder>, 'JSON_FORMAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONFormat'>>, 'J_S_O_N_OBJECT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObject'>>, 'J_S_O_N_OBJECT_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONObjectAgg'>>, 'J_S_O_N_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONTable'>>, 'LAG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lag'>>, 'LAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Last'>>, 'LAST_DAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_DAY_OF_MONTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastDay'>>, 'LAST_VALUE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LastValue'>>, 'LEAD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lead'>>, 'LEAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Least'>>, 'LEFT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Left'>>, 'LENGTH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Length'>>, 'LEVENSHTEIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Levenshtein'>>, 'LIST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.List'>>, 'LN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ln'>>, 'LOG': <function build_logarithm>, 'LOGICAL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOL_AND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'BOOLAND_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalAnd'>>, 'LOGICAL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOL_OR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'BOOLOR_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LogicalOr'>>, 'LOWER': <function build_lower>, 'LCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'LOWER_HEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.LowerHex'>>, 'MD5': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5'>>, 'MD5_DIGEST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MD5Digest'>>, 'MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Map'>>, 'MAP_FROM_ENTRIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MapFromEntries'>>, 'MATCH_AGAINST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.MatchAgainst'>>, 'MAX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Max'>>, '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'>>, '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'>>, 'PAD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pad'>>, 'PARAMETERIZED_AGG': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParameterizedAgg'>>, 'PARSE_JSON': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'JSON_PARSE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ParseJSON'>>, 'PERCENTILE_CONT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileCont'>>, 'PERCENTILE_DISC': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PercentileDisc'>>, 'POSEXPLODE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Posexplode'>>, 'POSEXPLODE_OUTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.PosexplodeOuter'>>, 'POWER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'POW': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Pow'>>, 'PREDICT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Predict'>>, 'QUANTILE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quantile'>>, 'QUARTER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Quarter'>>, 'RAND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rand'>>, 'RANDOM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Rand'>>, 'RANDN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Randn'>>, 'RANGE_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RangeN'>>, 'READ_CSV': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ReadCSV'>>, 'REDUCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Reduce'>>, 'REGEXP_EXTRACT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpExtract'>>, 'REGEXP_I_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpILike'>>, 'REGEXP_LIKE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpLike'>>, 'REGEXP_REPLACE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpReplace'>>, 'REGEXP_SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RegexpSplit'>>, 'REPEAT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Repeat'>>, 'RIGHT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Right'>>, 'ROUND': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Round'>>, 'ROW_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.RowNumber'>>, 'SHA': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA1': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA'>>, 'SHA2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SHA2'>>, 'SAFE_DIVIDE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SafeDivide'>>, 'SIGN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SIGNUM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Sign'>>, 'SORT_ARRAY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.SortArray'>>, 'SPLIT': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Split'>>, '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_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'>>, '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_MAP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToMap'>>, 'TO_NUMBER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ToNumber'>>, 'TRANSFORM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Transform'>>, 'TRIM': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Trim'>>, 'TRY': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Try'>>, 'TRY_CAST': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TryCast'>>, 'TS_OR_DI_TO_DI': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDiToDi'>>, 'TS_OR_DS_ADD': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsAdd'>>, 'TS_OR_DS_DIFF': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsDiff'>>, 'TS_OR_DS_TO_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToDate'>>, 'TS_OR_DS_TO_DATE_STR': <function Parser.<lambda>>, 'TS_OR_DS_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTime'>>, 'TS_OR_DS_TO_TIMESTAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.TsOrDsToTimestamp'>>, 'UNHEX': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Unhex'>>, 'UNIX_DATE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixDate'>>, 'UNIX_TO_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToStr'>>, 'UNIX_TO_TIME': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTime'>>, 'UNIX_TO_TIME_STR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.UnixToTimeStr'>>, 'UNNEST': <function Parser.<lambda>>, 'UPPER': <function build_upper>, 'UCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Upper'>>, 'VAR_MAP': <function build_var_map>, 'VARIANCE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VAR_SAMP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Variance'>>, 'VARIANCE_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'VAR_POP': <bound method Func.from_arg_list of <class 'sqlglot.expressions.VariancePop'>>, 'WEEK': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Week'>>, 'WEEK_OF_YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'WEEKOFYEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.WeekOfYear'>>, 'WHEN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.When'>>, 'X_M_L_TABLE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.XMLTable'>>, 'XOR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Xor'>>, 'YEAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Year'>>, '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>>, 'MOD': <function build_mod>, 'RPAD': <function Parser.<lambda>>, 'RIGHTPAD': <function Parser.<lambda>>, 'SCOPE_RESOLUTION': <function Parser.<lambda>>, 'TO_HEX': <function build_hex>}
NO_PAREN_FUNCTIONS = {<TokenType.CURRENT_DATE: 'CURRENT_DATE'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>: <class 'sqlglot.expressions.CurrentTime'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>: <class 'sqlglot.expressions.CurrentTimestamp'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>: <class 'sqlglot.expressions.CurrentUser'>}
STRUCT_TYPE_TOKENS = {<TokenType.NESTED: 'NESTED'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.STRUCT: 'STRUCT'>}
NESTED_TYPE_TOKENS = {<TokenType.MAP: 'MAP'>, <TokenType.NESTED: 'NESTED'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.LIST: 'LIST'>, <TokenType.STRUCT: 'STRUCT'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM: 'ENUM'>, <TokenType.ENUM8: 'ENUM8'>}
AGGREGATE_TYPE_TOKENS = {<TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>}
TYPE_TOKENS = {<TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.XML: 'XML'>, <TokenType.UUID: 'UUID'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATE: 'DATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT: 'INT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.JSON: 'JSON'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INT256: 'INT256'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LIST: 'LIST'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NESTED: 'NESTED'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.MAP: 'MAP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UINT: 'UINT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NAME: 'NAME'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.INET: 'INET'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULL: 'NULL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>}
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.SLASH: 'SLASH'>, <TokenType.NOT: 'NOT'>, <TokenType.DOT: 'DOT'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.AMP: 'AMP'>, <TokenType.COLON: 'COLON'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.GT: 'GT'>, <TokenType.MOD: 'MOD'>, <TokenType.STAR: 'STAR'>, <TokenType.EQ: 'EQ'>, <TokenType.TILDA: 'TILDA'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.PLUS: 'PLUS'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.DASH: 'DASH'>, <TokenType.HASH: 'HASH'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.COMMA: 'COMMA'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.CARET: 'CARET'>, <TokenType.PIPE: 'PIPE'>, <TokenType.LT: 'LT'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.SELECT: 'SELECT'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.R_BRACE: 'R_BRACE'>}
DB_CREATABLES = {<TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.MODEL: 'MODEL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.TAG: 'TAG'>, <TokenType.TABLE: 'TABLE'>}
CREATABLES = {<TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.VIEW: 'VIEW'>, <TokenType.MODEL: 'MODEL'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TAG: 'TAG'>, <TokenType.TABLE: 'TABLE'>, <TokenType.INDEX: 'INDEX'>}
ID_VAR_TOKENS = {<TokenType.ESCAPE: 'ESCAPE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.DESC: 'DESC'>, <TokenType.TOP: 'TOP'>, <TokenType.USE: 'USE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ANTI: 'ANTI'>, <TokenType.LOAD: 'LOAD'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.SOME: 'SOME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.XML: 'XML'>, <TokenType.DIV: 'DIV'>, <TokenType.UUID: 'UUID'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.KILL: 'KILL'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DATE: 'DATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.ASOF: 'ASOF'>, <TokenType.IS: 'IS'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FIRST: 'FIRST'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.ROWS: 'ROWS'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT: 'INT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MODEL: 'MODEL'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.IPV6: 'IPV6'>, <TokenType.COPY: 'COPY'>, <TokenType.SEMI: 'SEMI'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.FINAL: 'FINAL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SHOW: 'SHOW'>, <TokenType.NEXT: 'NEXT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.JSON: 'JSON'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SET: 'SET'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.VAR: 'VAR'>, <TokenType.ASC: 'ASC'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INT256: 'INT256'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LIST: 'LIST'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.TRUE: 'TRUE'>, <TokenType.MAP: 'MAP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INDEX: 'INDEX'>, <TokenType.LEFT: 'LEFT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.END: 'END'>, <TokenType.FULL: 'FULL'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.UINT: 'UINT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.APPLY: 'APPLY'>, <TokenType.NAME: 'NAME'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.ROW: 'ROW'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INET: 'INET'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ANY: 'ANY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULL: 'NULL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.TAG: 'TAG'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OFFSET: 'OFFSET'>}
INTERVAL_VARS = {<TokenType.ESCAPE: 'ESCAPE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.DESC: 'DESC'>, <TokenType.TOP: 'TOP'>, <TokenType.USE: 'USE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ANTI: 'ANTI'>, <TokenType.LOAD: 'LOAD'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.SOME: 'SOME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.XML: 'XML'>, <TokenType.DIV: 'DIV'>, <TokenType.UUID: 'UUID'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.KILL: 'KILL'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DATE: 'DATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.ASOF: 'ASOF'>, <TokenType.IS: 'IS'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FIRST: 'FIRST'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.ROWS: 'ROWS'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT: 'INT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MODEL: 'MODEL'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.IPV6: 'IPV6'>, <TokenType.COPY: 'COPY'>, <TokenType.SEMI: 'SEMI'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.FINAL: 'FINAL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SHOW: 'SHOW'>, <TokenType.NEXT: 'NEXT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.JSON: 'JSON'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SET: 'SET'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.VAR: 'VAR'>, <TokenType.ASC: 'ASC'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INT256: 'INT256'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LIST: 'LIST'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.TRUE: 'TRUE'>, <TokenType.MAP: 'MAP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INDEX: 'INDEX'>, <TokenType.LEFT: 'LEFT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.FULL: 'FULL'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.UINT: 'UINT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.APPLY: 'APPLY'>, <TokenType.NAME: 'NAME'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.ROW: 'ROW'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INET: 'INET'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ANY: 'ANY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULL: 'NULL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.TAG: 'TAG'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OFFSET: 'OFFSET'>}
TABLE_ALIAS_TOKENS = {<TokenType.ESCAPE: 'ESCAPE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.DESC: 'DESC'>, <TokenType.TOP: 'TOP'>, <TokenType.USE: 'USE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.LOAD: 'LOAD'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.SOME: 'SOME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.XML: 'XML'>, <TokenType.DIV: 'DIV'>, <TokenType.UUID: 'UUID'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.KILL: 'KILL'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DATE: 'DATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.IS: 'IS'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FIRST: 'FIRST'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.ROWS: 'ROWS'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT: 'INT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MODEL: 'MODEL'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.IPV6: 'IPV6'>, <TokenType.COPY: 'COPY'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.FINAL: 'FINAL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SHOW: 'SHOW'>, <TokenType.NEXT: 'NEXT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.JSON: 'JSON'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SET: 'SET'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.VAR: 'VAR'>, <TokenType.ASC: 'ASC'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INT256: 'INT256'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LIST: 'LIST'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.TRUE: 'TRUE'>, <TokenType.MAP: 'MAP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INDEX: 'INDEX'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.END: 'END'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.UINT: 'UINT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NAME: 'NAME'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.ROW: 'ROW'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INET: 'INET'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ANY: 'ANY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULL: 'NULL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.TAG: 'TAG'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>}
ALIAS_TOKENS = {<TokenType.ESCAPE: 'ESCAPE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.DESC: 'DESC'>, <TokenType.TOP: 'TOP'>, <TokenType.USE: 'USE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ANTI: 'ANTI'>, <TokenType.LOAD: 'LOAD'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.SOME: 'SOME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.XML: 'XML'>, <TokenType.DIV: 'DIV'>, <TokenType.UUID: 'UUID'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.KILL: 'KILL'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DATE: 'DATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.ASOF: 'ASOF'>, <TokenType.IS: 'IS'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FIRST: 'FIRST'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.ROWS: 'ROWS'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT: 'INT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MODEL: 'MODEL'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.IPV6: 'IPV6'>, <TokenType.COPY: 'COPY'>, <TokenType.SEMI: 'SEMI'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.FINAL: 'FINAL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SHOW: 'SHOW'>, <TokenType.NEXT: 'NEXT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.JSON: 'JSON'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SET: 'SET'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.VAR: 'VAR'>, <TokenType.ASC: 'ASC'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INT256: 'INT256'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LIST: 'LIST'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.TRUE: 'TRUE'>, <TokenType.MAP: 'MAP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INDEX: 'INDEX'>, <TokenType.LEFT: 'LEFT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.END: 'END'>, <TokenType.FULL: 'FULL'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.UINT: 'UINT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.APPLY: 'APPLY'>, <TokenType.NAME: 'NAME'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.ROW: 'ROW'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INET: 'INET'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ANY: 'ANY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULL: 'NULL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.TAG: 'TAG'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OFFSET: 'OFFSET'>}
ARRAY_CONSTRUCTORS = {'ARRAY': <class 'sqlglot.expressions.Array'>, 'LIST': <class 'sqlglot.expressions.List'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.ESCAPE: 'ESCAPE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.DESC: 'DESC'>, <TokenType.TOP: 'TOP'>, <TokenType.USE: 'USE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.LOAD: 'LOAD'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.SOME: 'SOME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.XML: 'XML'>, <TokenType.DIV: 'DIV'>, <TokenType.UUID: 'UUID'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.KILL: 'KILL'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DATE: 'DATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FIRST: 'FIRST'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.ROWS: 'ROWS'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT: 'INT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MODEL: 'MODEL'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.IPV6: 'IPV6'>, <TokenType.COPY: 'COPY'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.FINAL: 'FINAL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SHOW: 'SHOW'>, <TokenType.NEXT: 'NEXT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.JSON: 'JSON'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SET: 'SET'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.VAR: 'VAR'>, <TokenType.ASC: 'ASC'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INT256: 'INT256'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LIST: 'LIST'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.TRUE: 'TRUE'>, <TokenType.MAP: 'MAP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INDEX: 'INDEX'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.END: 'END'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.UINT: 'UINT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NAME: 'NAME'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.ROW: 'ROW'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INET: 'INET'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ANY: 'ANY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULL: 'NULL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.TAG: 'TAG'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>}
UPDATE_ALIAS_TOKENS = {<TokenType.ESCAPE: 'ESCAPE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.DESC: 'DESC'>, <TokenType.TOP: 'TOP'>, <TokenType.USE: 'USE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.LOAD: 'LOAD'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.SOME: 'SOME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.XML: 'XML'>, <TokenType.DIV: 'DIV'>, <TokenType.UUID: 'UUID'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.KILL: 'KILL'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DATE: 'DATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.IS: 'IS'>, <TokenType.FIRST: 'FIRST'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.ROWS: 'ROWS'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT: 'INT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MODEL: 'MODEL'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.IPV6: 'IPV6'>, <TokenType.COPY: 'COPY'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.FINAL: 'FINAL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SHOW: 'SHOW'>, <TokenType.NEXT: 'NEXT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.JSON: 'JSON'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.VAR: 'VAR'>, <TokenType.ASC: 'ASC'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INT256: 'INT256'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LIST: 'LIST'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.TRUE: 'TRUE'>, <TokenType.MAP: 'MAP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INDEX: 'INDEX'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.END: 'END'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.UINT: 'UINT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.NAME: 'NAME'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.ROW: 'ROW'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INET: 'INET'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ANY: 'ANY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULL: 'NULL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.TAG: 'TAG'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>}
TRIM_TYPES = {'TRAILING', 'BOTH', 'LEADING'}
FUNC_TOKENS = {<TokenType.REPLACE: 'REPLACE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.SOME: 'SOME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.FILTER: 'FILTER'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.XML: 'XML'>, <TokenType.UUID: 'UUID'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DATE: 'DATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FIRST: 'FIRST'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT: 'INT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.UINT128: 'UINT128'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.IPV6: 'IPV6'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.JSON: 'JSON'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.VAR: 'VAR'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.ALL: 'ALL'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.INSERT: 'INSERT'>, <TokenType.INT256: 'INT256'>, <TokenType.MERGE: 'MERGE'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LIST: 'LIST'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NESTED: 'NESTED'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.GLOB: 'GLOB'>, <TokenType.MAP: 'MAP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INDEX: 'INDEX'>, <TokenType.LEFT: 'LEFT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.UINT: 'UINT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.LIKE: 'LIKE'>, <TokenType.NAME: 'NAME'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.ROW: 'ROW'>, <TokenType.INET: 'INET'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ANY: 'ANY'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULL: 'NULL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.XOR: 'XOR'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OFFSET: 'OFFSET'>}
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.TIMETZ: 'TIMETZ'>, <TokenType.TIME: 'TIME'>}
TIMESTAMPS = {<TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>}
SET_OPERATIONS = {<TokenType.INTERSECT: 'INTERSECT'>, <TokenType.EXCEPT: 'EXCEPT'>, <TokenType.UNION: 'UNION'>}
JOIN_METHODS = {<TokenType.POSITIONAL: 'POSITIONAL'>, <TokenType.ASOF: 'ASOF'>, <TokenType.NATURAL: 'NATURAL'>}
JOIN_SIDES = {<TokenType.FULL: 'FULL'>, <TokenType.LEFT: 'LEFT'>, <TokenType.RIGHT: 'RIGHT'>}
JOIN_KINDS = {<TokenType.SEMI: 'SEMI'>, <TokenType.OUTER: 'OUTER'>, <TokenType.CROSS: 'CROSS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.INNER: 'INNER'>, <TokenType.STRAIGHT_JOIN: 'STRAIGHT_JOIN'>}
JOIN_HINTS: Set[str] = set()
LAMBDAS = {<TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.FARROW: 'FARROW'>: <function Parser.<lambda>>}
COLUMN_OPERATORS = {<TokenType.DOT: 'DOT'>: None, <TokenType.DCOLON: 'DCOLON'>: <function Parser.<lambda>>, <TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.DARROW: 'DARROW'>: <function Parser.<lambda>>, <TokenType.HASH_ARROW: 'HASH_ARROW'>: <function Parser.<lambda>>, <TokenType.DHASH_ARROW: 'DHASH_ARROW'>: <function Parser.<lambda>>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>}
EXPRESSION_PARSERS = {<class 'sqlglot.expressions.Cluster'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Column'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Condition'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.DataType'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Expression'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.From'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Group'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Having'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Identifier'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Join'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lambda'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Lateral'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Limit'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Offset'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Order'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Ordered'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Properties'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Qualify'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Returning'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Select'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Sort'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Table'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.TableAlias'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.When'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Where'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.Window'>: <function Parser.<lambda>>, <class 'sqlglot.expressions.With'>: <function Parser.<lambda>>, 'JOIN_TYPE': <function Parser.<lambda>>}
STATEMENT_PARSERS = {<TokenType.ALTER: 'ALTER'>: <function Parser.<lambda>>, <TokenType.BEGIN: 'BEGIN'>: <function Parser.<lambda>>, <TokenType.CACHE: 'CACHE'>: <function Parser.<lambda>>, <TokenType.COMMENT: 'COMMENT'>: <function Parser.<lambda>>, <TokenType.COMMIT: 'COMMIT'>: <function Parser.<lambda>>, <TokenType.COPY: 'COPY'>: <function Parser.<lambda>>, <TokenType.CREATE: 'CREATE'>: <function Parser.<lambda>>, <TokenType.DELETE: 'DELETE'>: <function Parser.<lambda>>, <TokenType.DESC: 'DESC'>: <function Parser.<lambda>>, <TokenType.DESCRIBE: 'DESCRIBE'>: <function Parser.<lambda>>, <TokenType.DROP: 'DROP'>: <function Parser.<lambda>>, <TokenType.INSERT: 'INSERT'>: <function Parser.<lambda>>, <TokenType.KILL: 'KILL'>: <function Parser.<lambda>>, <TokenType.LOAD: 'LOAD'>: <function Parser.<lambda>>, <TokenType.MERGE: 'MERGE'>: <function Parser.<lambda>>, <TokenType.PIVOT: 'PIVOT'>: <function Parser.<lambda>>, <TokenType.PRAGMA: 'PRAGMA'>: <function Parser.<lambda>>, <TokenType.REFRESH: 'REFRESH'>: <function Parser.<lambda>>, <TokenType.ROLLBACK: 'ROLLBACK'>: <function Parser.<lambda>>, <TokenType.SET: 'SET'>: <function Parser.<lambda>>, <TokenType.TRUNCATE: 'TRUNCATE'>: <function Parser.<lambda>>, <TokenType.UNCACHE: 'UNCACHE'>: <function Parser.<lambda>>, <TokenType.UPDATE: 'UPDATE'>: <function Parser.<lambda>>, <TokenType.USE: 'USE'>: <function Parser.<lambda>>, <TokenType.SEMICOLON: 'SEMICOLON'>: <function Parser.<lambda>>}
UNARY_PARSERS = {<TokenType.PLUS: 'PLUS'>: <function Parser.<lambda>>, <TokenType.NOT: 'NOT'>: <function Parser.<lambda>>, <TokenType.TILDA: 'TILDA'>: <function Parser.<lambda>>, <TokenType.DASH: 'DASH'>: <function Parser.<lambda>>, <TokenType.PIPE_SLASH: 'PIPE_SLASH'>: <function Parser.<lambda>>, <TokenType.DPIPE_SLASH: 'DPIPE_SLASH'>: <function Parser.<lambda>>}
STRING_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>}
NUMERIC_PARSERS = {<TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>}
PRIMARY_PARSERS = {<TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>, <TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>, <TokenType.INTRODUCER: 'INTRODUCER'>: <function Parser.<lambda>>, <TokenType.NULL: 'NULL'>: <function Parser.<lambda>>, <TokenType.TRUE: 'TRUE'>: <function Parser.<lambda>>, <TokenType.FALSE: 'FALSE'>: <function Parser.<lambda>>, <TokenType.SESSION_PARAMETER: 'SESSION_PARAMETER'>: <function Parser.<lambda>>, <TokenType.STAR: 'STAR'>: <function Parser.<lambda>>}
PLACEHOLDER_PARSERS = {<TokenType.PLACEHOLDER: 'PLACEHOLDER'>: <function Parser.<lambda>>, <TokenType.PARAMETER: 'PARAMETER'>: <function Parser.<lambda>>, <TokenType.COLON: 'COLON'>: <function Parser.<lambda>>}
RANGE_PARSERS = {<TokenType.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.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>>, 'DYNAMIC': <function Parser.<lambda>>, 'DISTKEY': <function Parser.<lambda>>, 'DISTSTYLE': <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>>, 'ROW': <function Parser.<lambda>>, 'ROW_FORMAT': <function Parser.<lambda>>, 'SAMPLE': <function Parser.<lambda>>, 'SECURE': <function Parser.<lambda>>, 'SET': <function Parser.<lambda>>, 'SETTINGS': <function Parser.<lambda>>, 'SHARING': <function Parser.<lambda>>, 'SORTKEY': <function Parser.<lambda>>, 'SOURCE': <function Parser.<lambda>>, 'STABLE': <function Parser.<lambda>>, 'STORED': <function Parser.<lambda>>, 'SYSTEM_VERSIONING': <function Parser.<lambda>>, 'TBLPROPERTIES': <function Parser.<lambda>>, 'TEMP': <function Parser.<lambda>>, 'TEMPORARY': <function Parser.<lambda>>, 'TO': <function Parser.<lambda>>, 'TRANSIENT': <function Parser.<lambda>>, 'TRANSFORM': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'USING': <function Parser.<lambda>>, 'UNLOGGED': <function Parser.<lambda>>, 'VOLATILE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
CONSTRAINT_PARSERS = {'AUTOINCREMENT': <function Parser.<lambda>>, 'AUTO_INCREMENT': <function Parser.<lambda>>, 'CASESPECIFIC': <function Parser.<lambda>>, 'CHARACTER SET': <function Parser.<lambda>>, 'CHECK': <function Parser.<lambda>>, 'COLLATE': <function Parser.<lambda>>, 'COMMENT': <function Parser.<lambda>>, 'COMPRESS': <function Parser.<lambda>>, 'CLUSTERED': <function Parser.<lambda>>, 'NONCLUSTERED': <function Parser.<lambda>>, 'DEFAULT': <function Parser.<lambda>>, 'ENCODE': <function Parser.<lambda>>, 'EPHEMERAL': <function Parser.<lambda>>, 'EXCLUDE': <function Parser.<lambda>>, 'FOREIGN KEY': <function Parser.<lambda>>, 'FORMAT': <function Parser.<lambda>>, 'GENERATED': <function Parser.<lambda>>, 'IDENTITY': <function Parser.<lambda>>, 'INLINE': <function Parser.<lambda>>, 'LIKE': <function Parser.<lambda>>, 'NOT': <function Parser.<lambda>>, 'NULL': <function Parser.<lambda>>, 'ON': <function Parser.<lambda>>, 'PATH': <function Parser.<lambda>>, 'PERIOD': <function Parser.<lambda>>, 'PRIMARY KEY': <function Parser.<lambda>>, 'REFERENCES': <function Parser.<lambda>>, 'TITLE': <function Parser.<lambda>>, 'TTL': <function Parser.<lambda>>, 'UNIQUE': <function Parser.<lambda>>, 'UPPERCASE': <function Parser.<lambda>>, 'WITH': <function Parser.<lambda>>}
ALTER_PARSERS = {'ADD': <function Parser.<lambda>>, '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>>}
ALTER_ALTER_PARSERS = {'DISTKEY': <function Parser.<lambda>>, 'DISTSTYLE': <function Parser.<lambda>>, 'SORTKEY': <function Parser.<lambda>>, 'COMPOUND': <function Parser.<lambda>>}
SCHEMA_UNNAMED_CONSTRAINTS = {'PRIMARY KEY', 'PERIOD', 'CHECK', 'UNIQUE', 'LIKE', 'EXCLUDE', 'FOREIGN KEY'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'CONNECT_BY_ROOT': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>, 'NEXT': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.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>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <function Parser.<lambda>>, 'GAP_FILL': <function Parser.<lambda>>, 'JSON_OBJECT': <function Parser.<lambda>>, 'JSON_OBJECTAGG': <function Parser.<lambda>>, 'JSON_TABLE': <function Parser.<lambda>>, 'MATCH': <function Parser.<lambda>>, 'OPENJSON': <function Parser.<lambda>>, 'POSITION': <function Parser.<lambda>>, 'PREDICT': <function Parser.<lambda>>, 'SAFE_CAST': <function Parser.<lambda>>, 'STRING_AGG': <function Parser.<lambda>>, 'SUBSTRING': <function Parser.<lambda>>, 'TRIM': <function Parser.<lambda>>, 'TRY_CAST': <function Parser.<lambda>>, 'TRY_CONVERT': <function Parser.<lambda>>}
QUERY_MODIFIER_PARSERS = {<TokenType.MATCH_RECOGNIZE: 'MATCH_RECOGNIZE'>: <function Parser.<lambda>>, <TokenType.PREWHERE: 'PREWHERE'>: <function Parser.<lambda>>, <TokenType.WHERE: 'WHERE'>: <function Parser.<lambda>>, <TokenType.GROUP_BY: 'GROUP_BY'>: <function Parser.<lambda>>, <TokenType.HAVING: 'HAVING'>: <function Parser.<lambda>>, <TokenType.QUALIFY: 'QUALIFY'>: <function Parser.<lambda>>, <TokenType.WINDOW: 'WINDOW'>: <function Parser.<lambda>>, <TokenType.ORDER_BY: 'ORDER_BY'>: <function Parser.<lambda>>, <TokenType.LIMIT: 'LIMIT'>: <function Parser.<lambda>>, <TokenType.FETCH: 'FETCH'>: <function Parser.<lambda>>, <TokenType.OFFSET: 'OFFSET'>: <function Parser.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>, <TokenType.LOCK: 'LOCK'>: <function Parser.<lambda>>, <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>: <function Parser.<lambda>>, <TokenType.USING: 'USING'>: <function Parser.<lambda>>, <TokenType.CLUSTER_BY: 'CLUSTER_BY'>: <function Parser.<lambda>>, <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>: <function Parser.<lambda>>, <TokenType.SORT_BY: 'SORT_BY'>: <function Parser.<lambda>>, <TokenType.CONNECT_BY: 'CONNECT_BY'>: <function Parser.<lambda>>, <TokenType.START_WITH: 'START_WITH'>: <function Parser.<lambda>>}
SET_PARSERS = {'GLOBAL': <function Parser.<lambda>>, 'LOCAL': <function Parser.<lambda>>, 'SESSION': <function Parser.<lambda>>, 'TRANSACTION': <function Parser.<lambda>>}
SHOW_PARSERS: Dict[str, Callable] = {}
TYPE_LITERAL_PARSERS = {<Type.JSON: 'JSON'>: <function Parser.<lambda>>}
DDL_SELECT_TOKENS = {<TokenType.WITH: 'WITH'>, <TokenType.SELECT: 'SELECT'>, <TokenType.L_PAREN: 'L_PAREN'>}
PRE_VOLATILE_TOKENS = {<TokenType.UNIQUE: 'UNIQUE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.CREATE: 'CREATE'>}
TRANSACTION_KIND = {'EXCLUSIVE', 'DEFERRED', 'IMMEDIATE'}
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': ()}
KEY_CONSTRAINT_OPTIONS: Dict[str, Sequence[Union[Sequence[str], str]]] = {'NOT': ('ENFORCED',), 'MATCH': ('FULL', 'PARTIAL', 'SIMPLE'), 'INITIALLY': ('DEFERRED', 'IMMEDIATE'), 'DEFERRABLE': (), 'NORELY': ()}
INSERT_ALTERNATIVES = {'ABORT', 'REPLACE', 'IGNORE', 'FAIL', 'ROLLBACK'}
CLONE_KEYWORDS = {'COPY', 'CLONE'}
HISTORICAL_DATA_PREFIX = {'END', 'BEFORE', 'AT'}
HISTORICAL_DATA_KIND = {'STREAM', 'STATEMENT', 'TIMESTAMP', 'OFFSET'}
OPCLASS_FOLLOW_KEYWORDS = {'DESC', 'NULLS', 'ASC', 'WITH'}
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 = {'SCHEMABINDING', 'VIEW_METADATA', 'ENCRYPTION'}
WINDOW_ALIAS_TOKENS = {<TokenType.ESCAPE: 'ESCAPE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.DESC: 'DESC'>, <TokenType.TOP: 'TOP'>, <TokenType.USE: 'USE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ANTI: 'ANTI'>, <TokenType.LOAD: 'LOAD'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.SOME: 'SOME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.XML: 'XML'>, <TokenType.DIV: 'DIV'>, <TokenType.UUID: 'UUID'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.KILL: 'KILL'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DATE: 'DATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.ASOF: 'ASOF'>, <TokenType.IS: 'IS'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FIRST: 'FIRST'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT: 'INT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MODEL: 'MODEL'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.IPV6: 'IPV6'>, <TokenType.COPY: 'COPY'>, <TokenType.SEMI: 'SEMI'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.FINAL: 'FINAL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SHOW: 'SHOW'>, <TokenType.NEXT: 'NEXT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.JSON: 'JSON'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SET: 'SET'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.VAR: 'VAR'>, <TokenType.ASC: 'ASC'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INT256: 'INT256'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LIST: 'LIST'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.TRUE: 'TRUE'>, <TokenType.MAP: 'MAP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INDEX: 'INDEX'>, <TokenType.LEFT: 'LEFT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.END: 'END'>, <TokenType.FULL: 'FULL'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.UINT: 'UINT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.APPLY: 'APPLY'>, <TokenType.NAME: 'NAME'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.ROW: 'ROW'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INET: 'INET'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ANY: 'ANY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULL: 'NULL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.TAG: 'TAG'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OFFSET: 'OFFSET'>}
WINDOW_BEFORE_PAREN_TOKENS = {<TokenType.OVER: 'OVER'>}
WINDOW_SIDES = {'FOLLOWING', 'PRECEDING'}
JSON_KEY_VALUE_SEPARATOR_TOKENS = {<TokenType.COMMA: 'COMMA'>, <TokenType.COLON: 'COLON'>, <TokenType.IS: 'IS'>}
FETCH_TOKENS = {<TokenType.ESCAPE: 'ESCAPE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.DESC: 'DESC'>, <TokenType.TOP: 'TOP'>, <TokenType.USE: 'USE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ANTI: 'ANTI'>, <TokenType.LOAD: 'LOAD'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.SOME: 'SOME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.XML: 'XML'>, <TokenType.DIV: 'DIV'>, <TokenType.UUID: 'UUID'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.KILL: 'KILL'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DATE: 'DATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.ASOF: 'ASOF'>, <TokenType.IS: 'IS'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FIRST: 'FIRST'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT: 'INT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MODEL: 'MODEL'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.IPV6: 'IPV6'>, <TokenType.COPY: 'COPY'>, <TokenType.SEMI: 'SEMI'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.FINAL: 'FINAL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SHOW: 'SHOW'>, <TokenType.NEXT: 'NEXT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.JSON: 'JSON'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SET: 'SET'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.VAR: 'VAR'>, <TokenType.ASC: 'ASC'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INT256: 'INT256'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LIST: 'LIST'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.TRUE: 'TRUE'>, <TokenType.MAP: 'MAP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INDEX: 'INDEX'>, <TokenType.LEFT: 'LEFT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.END: 'END'>, <TokenType.FULL: 'FULL'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.UINT: 'UINT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.APPLY: 'APPLY'>, <TokenType.NAME: 'NAME'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INET: 'INET'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ANY: 'ANY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULL: 'NULL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.TAG: 'TAG'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OFFSET: 'OFFSET'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.KEY: 'KEY'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.INDEX: 'INDEX'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.ESCAPE: 'ESCAPE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.DESC: 'DESC'>, <TokenType.TOP: 'TOP'>, <TokenType.USE: 'USE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.KEEP: 'KEEP'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UINT256: 'UINT256'>, <TokenType.ANTI: 'ANTI'>, <TokenType.LOAD: 'LOAD'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.SOME: 'SOME'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.FILTER: 'FILTER'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.XML: 'XML'>, <TokenType.DIV: 'DIV'>, <TokenType.UUID: 'UUID'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.ENUM: 'ENUM'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.KILL: 'KILL'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.DELETE: 'DELETE'>, <TokenType.DATE: 'DATE'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.FALSE: 'FALSE'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.ASOF: 'ASOF'>, <TokenType.IS: 'IS'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.FIRST: 'FIRST'>, <TokenType.STORAGE_INTEGRATION: 'STORAGE_INTEGRATION'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.CHAR: 'CHAR'>, <TokenType.ROWS: 'ROWS'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.INT: 'INT'>, <TokenType.DATE32: 'DATE32'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.MODEL: 'MODEL'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.UINT128: 'UINT128'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.IPV6: 'IPV6'>, <TokenType.COPY: 'COPY'>, <TokenType.SEMI: 'SEMI'>, <TokenType.BPCHAR: 'BPCHAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.CASE: 'CASE'>, <TokenType.VIEW: 'VIEW'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.FINAL: 'FINAL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.SHOW: 'SHOW'>, <TokenType.NEXT: 'NEXT'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.JSON: 'JSON'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.SET: 'SET'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.VAR: 'VAR'>, <TokenType.ASC: 'ASC'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.TIME: 'TIME'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.ALL: 'ALL'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.CUBE: 'CUBE'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.BINARY: 'BINARY'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.INT256: 'INT256'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.BIT: 'BIT'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.LIST: 'LIST'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.TRUNCATE: 'TRUNCATE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NESTED: 'NESTED'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.INT128: 'INT128'>, <TokenType.TRUE: 'TRUE'>, <TokenType.MAP: 'MAP'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.INDEX: 'INDEX'>, <TokenType.LEFT: 'LEFT'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.JSONB: 'JSONB'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.STREAMLIT: 'STREAMLIT'>, <TokenType.END: 'END'>, <TokenType.FULL: 'FULL'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.UINT: 'UINT'>, <TokenType.TDIGEST: 'TDIGEST'>, <TokenType.APPLY: 'APPLY'>, <TokenType.NAME: 'NAME'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.ROW: 'ROW'>, <TokenType.ROLLUP: 'ROLLUP'>, <TokenType.INET: 'INET'>, <TokenType.FUNCTION: 'FUNCTION'>, <TokenType.ANY: 'ANY'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.VECTOR: 'VECTOR'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.NULL: 'NULL'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.TAG: 'TAG'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SEQUENCE: 'SEQUENCE'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.SIMPLEAGGREGATEFUNCTION: 'SIMPLEAGGREGATEFUNCTION'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.AGGREGATEFUNCTION: 'AGGREGATEFUNCTION'>, <TokenType.WAREHOUSE: 'WAREHOUSE'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.OFFSET: 'OFFSET'>}
SELECT_START_TOKENS = {<TokenType.WITH: 'WITH'>, <TokenType.SELECT: 'SELECT'>, <TokenType.L_PAREN: 'L_PAREN'>}
COPY_INTO_VARLEN_OPTIONS = {'FILE_FORMAT', 'FORMAT_OPTIONS', 'CREDENTIAL', 'COPY_OPTIONS'}
STRICT_CAST = True
PREFIXED_PIVOT_COLUMNS = False
IDENTIFY_PIVOT_STRINGS = False
LOG_DEFAULTS_TO_LN = False
ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
TABLESAMPLE_CSV = False
DEFAULT_SAMPLING_METHOD: Optional[str] = None
SET_REQUIRES_ASSIGNMENT_DELIMITER = True
TRIM_PATTERN_FIRST = False
STRING_ALIASES = False
MODIFIERS_ATTACHED_TO_SET_OP = True
SET_OP_MODIFIERS = {'offset', 'limit', 'order'}
NO_PAREN_IF_COMMANDS = True
JSON_ARROWS_REQUIRE_JSON_TYPE = False
COLON_IS_VARIANT_EXTRACT = False
VALUES_FOLLOWED_BY_PAREN = True
SUPPORTS_IMPLICIT_UNNEST = False
INTERVAL_SPANS = True
SUPPORTS_PARTITION_SELECTION = False
SHOW_TRIE: Dict = {}
SET_TRIE: Dict = {'GLOBAL': {0: True}, 'LOCAL': {0: True}, 'SESSION': {0: True}, 'TRANSACTION': {0: True}}
error_level
error_message_context
max_errors
dialect
def reset(self):
1293    def reset(self):
1294        self.sql = ""
1295        self.errors = []
1296        self._tokens = []
1297        self._index = 0
1298        self._curr = None
1299        self._next = None
1300        self._prev = None
1301        self._prev_comments = None
def parse( self, raw_tokens: List[sqlglot.tokens.Token], sql: Optional[str] = None) -> List[Optional[sqlglot.expressions.Expression]]:
1303    def parse(
1304        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1305    ) -> t.List[t.Optional[exp.Expression]]:
1306        """
1307        Parses a list of tokens and returns a list of syntax trees, one tree
1308        per parsed SQL statement.
1309
1310        Args:
1311            raw_tokens: The list of tokens.
1312            sql: The original SQL string, used to produce helpful debug messages.
1313
1314        Returns:
1315            The list of the produced syntax trees.
1316        """
1317        return self._parse(
1318            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1319        )

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]]:
1321    def parse_into(
1322        self,
1323        expression_types: exp.IntoType,
1324        raw_tokens: t.List[Token],
1325        sql: t.Optional[str] = None,
1326    ) -> t.List[t.Optional[exp.Expression]]:
1327        """
1328        Parses a list of tokens into a given Expression type. If a collection of Expression
1329        types is given instead, this method will try to parse the token list into each one
1330        of them, stopping at the first for which the parsing succeeds.
1331
1332        Args:
1333            expression_types: The expression type(s) to try and parse the token list into.
1334            raw_tokens: The list of tokens.
1335            sql: The original SQL string, used to produce helpful debug messages.
1336
1337        Returns:
1338            The target Expression.
1339        """
1340        errors = []
1341        for expression_type in ensure_list(expression_types):
1342            parser = self.EXPRESSION_PARSERS.get(expression_type)
1343            if not parser:
1344                raise TypeError(f"No parser registered for {expression_type}")
1345
1346            try:
1347                return self._parse(parser, raw_tokens, sql)
1348            except ParseError as e:
1349                e.errors[0]["into_expression"] = expression_type
1350                errors.append(e)
1351
1352        raise ParseError(
1353            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1354            errors=merge_errors(errors),
1355        ) 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:
1395    def check_errors(self) -> None:
1396        """Logs or raises any found errors, depending on the chosen error level setting."""
1397        if self.error_level == ErrorLevel.WARN:
1398            for error in self.errors:
1399                logger.error(str(error))
1400        elif self.error_level == ErrorLevel.RAISE and self.errors:
1401            raise ParseError(
1402                concat_messages(self.errors, self.max_errors),
1403                errors=merge_errors(self.errors),
1404            )

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:
1406    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1407        """
1408        Appends an error in the list of recorded errors or raises it, depending on the chosen
1409        error level setting.
1410        """
1411        token = token or self._curr or self._prev or Token.string("")
1412        start = token.start
1413        end = token.end + 1
1414        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1415        highlight = self.sql[start:end]
1416        end_context = self.sql[end : end + self.error_message_context]
1417
1418        error = ParseError.new(
1419            f"{message}. Line {token.line}, Col: {token.col}.\n"
1420            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1421            description=message,
1422            line=token.line,
1423            col=token.col,
1424            start_context=start_context,
1425            highlight=highlight,
1426            end_context=end_context,
1427        )
1428
1429        if self.error_level == ErrorLevel.IMMEDIATE:
1430            raise error
1431
1432        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:
1434    def expression(
1435        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1436    ) -> E:
1437        """
1438        Creates a new, validated Expression.
1439
1440        Args:
1441            exp_class: The expression class to instantiate.
1442            comments: An optional list of comments to attach to the expression.
1443            kwargs: The arguments to set for the expression along with their respective values.
1444
1445        Returns:
1446            The target expression.
1447        """
1448        instance = exp_class(**kwargs)
1449        instance.add_comments(comments) if comments else self._add_comments(instance)
1450        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:
1457    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1458        """
1459        Validates an Expression, making sure that all its mandatory arguments are set.
1460
1461        Args:
1462            expression: The expression to validate.
1463            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1464
1465        Returns:
1466            The validated expression.
1467        """
1468        if self.error_level != ErrorLevel.IGNORE:
1469            for error_message in expression.error_messages(args):
1470                self.raise_error(error_message)
1471
1472        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