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 typing_extensions import Literal
  16
  17    from sqlglot._typing import E
  18    from sqlglot.dialects.dialect import Dialect, DialectType
  19
  20logger = logging.getLogger("sqlglot")
  21
  22
  23def parse_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
  24    if len(args) == 1 and args[0].is_star:
  25        return exp.StarMap(this=args[0])
  26
  27    keys = []
  28    values = []
  29    for i in range(0, len(args), 2):
  30        keys.append(args[i])
  31        values.append(args[i + 1])
  32
  33    return exp.VarMap(
  34        keys=exp.Array(expressions=keys),
  35        values=exp.Array(expressions=values),
  36    )
  37
  38
  39def parse_like(args: t.List) -> exp.Escape | exp.Like:
  40    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
  41    return exp.Escape(this=like, expression=seq_get(args, 2)) if len(args) > 2 else like
  42
  43
  44def binary_range_parser(
  45    expr_type: t.Type[exp.Expression],
  46) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
  47    return lambda self, this: self._parse_escape(
  48        self.expression(expr_type, this=this, expression=self._parse_bitwise())
  49    )
  50
  51
  52def parse_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
  53    # Default argument order is base, expression
  54    this = seq_get(args, 0)
  55    expression = seq_get(args, 1)
  56
  57    if expression:
  58        if not dialect.LOG_BASE_FIRST:
  59            this, expression = expression, this
  60        return exp.Log(this=this, expression=expression)
  61
  62    return (exp.Ln if dialect.parser_class.LOG_DEFAULTS_TO_LN else exp.Log)(this=this)
  63
  64
  65class _Parser(type):
  66    def __new__(cls, clsname, bases, attrs):
  67        klass = super().__new__(cls, clsname, bases, attrs)
  68
  69        klass.SHOW_TRIE = new_trie(key.split(" ") for key in klass.SHOW_PARSERS)
  70        klass.SET_TRIE = new_trie(key.split(" ") for key in klass.SET_PARSERS)
  71
  72        return klass
  73
  74
  75class Parser(metaclass=_Parser):
  76    """
  77    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
  78
  79    Args:
  80        error_level: The desired error level.
  81            Default: ErrorLevel.IMMEDIATE
  82        error_message_context: Determines the amount of context to capture from a
  83            query string when displaying the error message (in number of characters).
  84            Default: 100
  85        max_errors: Maximum number of error messages to include in a raised ParseError.
  86            This is only relevant if error_level is ErrorLevel.RAISE.
  87            Default: 3
  88    """
  89
  90    FUNCTIONS: t.Dict[str, t.Callable] = {
  91        **{name: func.from_arg_list for name, func in exp.FUNCTION_BY_NAME.items()},
  92        "CONCAT": lambda args, dialect: exp.Concat(
  93            expressions=args,
  94            safe=not dialect.STRICT_STRING_CONCAT,
  95            coalesce=dialect.CONCAT_COALESCE,
  96        ),
  97        "CONCAT_WS": lambda args, dialect: exp.ConcatWs(
  98            expressions=args,
  99            safe=not dialect.STRICT_STRING_CONCAT,
 100            coalesce=dialect.CONCAT_COALESCE,
 101        ),
 102        "DATE_TO_DATE_STR": lambda args: exp.Cast(
 103            this=seq_get(args, 0),
 104            to=exp.DataType(this=exp.DataType.Type.TEXT),
 105        ),
 106        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
 107        "LIKE": parse_like,
 108        "LOG": parse_logarithm,
 109        "TIME_TO_TIME_STR": lambda args: exp.Cast(
 110            this=seq_get(args, 0),
 111            to=exp.DataType(this=exp.DataType.Type.TEXT),
 112        ),
 113        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
 114            this=exp.Cast(
 115                this=seq_get(args, 0),
 116                to=exp.DataType(this=exp.DataType.Type.TEXT),
 117            ),
 118            start=exp.Literal.number(1),
 119            length=exp.Literal.number(10),
 120        ),
 121        "VAR_MAP": parse_var_map,
 122    }
 123
 124    NO_PAREN_FUNCTIONS = {
 125        TokenType.CURRENT_DATE: exp.CurrentDate,
 126        TokenType.CURRENT_DATETIME: exp.CurrentDate,
 127        TokenType.CURRENT_TIME: exp.CurrentTime,
 128        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
 129        TokenType.CURRENT_USER: exp.CurrentUser,
 130    }
 131
 132    STRUCT_TYPE_TOKENS = {
 133        TokenType.NESTED,
 134        TokenType.STRUCT,
 135    }
 136
 137    NESTED_TYPE_TOKENS = {
 138        TokenType.ARRAY,
 139        TokenType.LOWCARDINALITY,
 140        TokenType.MAP,
 141        TokenType.NULLABLE,
 142        *STRUCT_TYPE_TOKENS,
 143    }
 144
 145    ENUM_TYPE_TOKENS = {
 146        TokenType.ENUM,
 147        TokenType.ENUM8,
 148        TokenType.ENUM16,
 149    }
 150
 151    TYPE_TOKENS = {
 152        TokenType.BIT,
 153        TokenType.BOOLEAN,
 154        TokenType.TINYINT,
 155        TokenType.UTINYINT,
 156        TokenType.SMALLINT,
 157        TokenType.USMALLINT,
 158        TokenType.INT,
 159        TokenType.UINT,
 160        TokenType.BIGINT,
 161        TokenType.UBIGINT,
 162        TokenType.INT128,
 163        TokenType.UINT128,
 164        TokenType.INT256,
 165        TokenType.UINT256,
 166        TokenType.MEDIUMINT,
 167        TokenType.UMEDIUMINT,
 168        TokenType.FIXEDSTRING,
 169        TokenType.FLOAT,
 170        TokenType.DOUBLE,
 171        TokenType.CHAR,
 172        TokenType.NCHAR,
 173        TokenType.VARCHAR,
 174        TokenType.NVARCHAR,
 175        TokenType.TEXT,
 176        TokenType.MEDIUMTEXT,
 177        TokenType.LONGTEXT,
 178        TokenType.MEDIUMBLOB,
 179        TokenType.LONGBLOB,
 180        TokenType.BINARY,
 181        TokenType.VARBINARY,
 182        TokenType.JSON,
 183        TokenType.JSONB,
 184        TokenType.INTERVAL,
 185        TokenType.TINYBLOB,
 186        TokenType.TINYTEXT,
 187        TokenType.TIME,
 188        TokenType.TIMETZ,
 189        TokenType.TIMESTAMP,
 190        TokenType.TIMESTAMP_S,
 191        TokenType.TIMESTAMP_MS,
 192        TokenType.TIMESTAMP_NS,
 193        TokenType.TIMESTAMPTZ,
 194        TokenType.TIMESTAMPLTZ,
 195        TokenType.DATETIME,
 196        TokenType.DATETIME64,
 197        TokenType.DATE,
 198        TokenType.DATE32,
 199        TokenType.INT4RANGE,
 200        TokenType.INT4MULTIRANGE,
 201        TokenType.INT8RANGE,
 202        TokenType.INT8MULTIRANGE,
 203        TokenType.NUMRANGE,
 204        TokenType.NUMMULTIRANGE,
 205        TokenType.TSRANGE,
 206        TokenType.TSMULTIRANGE,
 207        TokenType.TSTZRANGE,
 208        TokenType.TSTZMULTIRANGE,
 209        TokenType.DATERANGE,
 210        TokenType.DATEMULTIRANGE,
 211        TokenType.DECIMAL,
 212        TokenType.UDECIMAL,
 213        TokenType.BIGDECIMAL,
 214        TokenType.UUID,
 215        TokenType.GEOGRAPHY,
 216        TokenType.GEOMETRY,
 217        TokenType.HLLSKETCH,
 218        TokenType.HSTORE,
 219        TokenType.PSEUDO_TYPE,
 220        TokenType.SUPER,
 221        TokenType.SERIAL,
 222        TokenType.SMALLSERIAL,
 223        TokenType.BIGSERIAL,
 224        TokenType.XML,
 225        TokenType.YEAR,
 226        TokenType.UNIQUEIDENTIFIER,
 227        TokenType.USERDEFINED,
 228        TokenType.MONEY,
 229        TokenType.SMALLMONEY,
 230        TokenType.ROWVERSION,
 231        TokenType.IMAGE,
 232        TokenType.VARIANT,
 233        TokenType.OBJECT,
 234        TokenType.OBJECT_IDENTIFIER,
 235        TokenType.INET,
 236        TokenType.IPADDRESS,
 237        TokenType.IPPREFIX,
 238        TokenType.IPV4,
 239        TokenType.IPV6,
 240        TokenType.UNKNOWN,
 241        TokenType.NULL,
 242        *ENUM_TYPE_TOKENS,
 243        *NESTED_TYPE_TOKENS,
 244    }
 245
 246    SIGNED_TO_UNSIGNED_TYPE_TOKEN = {
 247        TokenType.BIGINT: TokenType.UBIGINT,
 248        TokenType.INT: TokenType.UINT,
 249        TokenType.MEDIUMINT: TokenType.UMEDIUMINT,
 250        TokenType.SMALLINT: TokenType.USMALLINT,
 251        TokenType.TINYINT: TokenType.UTINYINT,
 252        TokenType.DECIMAL: TokenType.UDECIMAL,
 253    }
 254
 255    SUBQUERY_PREDICATES = {
 256        TokenType.ANY: exp.Any,
 257        TokenType.ALL: exp.All,
 258        TokenType.EXISTS: exp.Exists,
 259        TokenType.SOME: exp.Any,
 260    }
 261
 262    RESERVED_TOKENS = {
 263        *Tokenizer.SINGLE_TOKENS.values(),
 264        TokenType.SELECT,
 265    }
 266
 267    DB_CREATABLES = {
 268        TokenType.DATABASE,
 269        TokenType.SCHEMA,
 270        TokenType.TABLE,
 271        TokenType.VIEW,
 272        TokenType.MODEL,
 273        TokenType.DICTIONARY,
 274    }
 275
 276    CREATABLES = {
 277        TokenType.COLUMN,
 278        TokenType.CONSTRAINT,
 279        TokenType.FUNCTION,
 280        TokenType.INDEX,
 281        TokenType.PROCEDURE,
 282        TokenType.FOREIGN_KEY,
 283        *DB_CREATABLES,
 284    }
 285
 286    # Tokens that can represent identifiers
 287    ID_VAR_TOKENS = {
 288        TokenType.VAR,
 289        TokenType.ANTI,
 290        TokenType.APPLY,
 291        TokenType.ASC,
 292        TokenType.AUTO_INCREMENT,
 293        TokenType.BEGIN,
 294        TokenType.CACHE,
 295        TokenType.CASE,
 296        TokenType.COLLATE,
 297        TokenType.COMMAND,
 298        TokenType.COMMENT,
 299        TokenType.COMMIT,
 300        TokenType.CONSTRAINT,
 301        TokenType.DEFAULT,
 302        TokenType.DELETE,
 303        TokenType.DESC,
 304        TokenType.DESCRIBE,
 305        TokenType.DICTIONARY,
 306        TokenType.DIV,
 307        TokenType.END,
 308        TokenType.EXECUTE,
 309        TokenType.ESCAPE,
 310        TokenType.FALSE,
 311        TokenType.FIRST,
 312        TokenType.FILTER,
 313        TokenType.FINAL,
 314        TokenType.FORMAT,
 315        TokenType.FULL,
 316        TokenType.IS,
 317        TokenType.ISNULL,
 318        TokenType.INTERVAL,
 319        TokenType.KEEP,
 320        TokenType.KILL,
 321        TokenType.LEFT,
 322        TokenType.LOAD,
 323        TokenType.MERGE,
 324        TokenType.NATURAL,
 325        TokenType.NEXT,
 326        TokenType.OFFSET,
 327        TokenType.OPERATOR,
 328        TokenType.ORDINALITY,
 329        TokenType.OVERLAPS,
 330        TokenType.OVERWRITE,
 331        TokenType.PARTITION,
 332        TokenType.PERCENT,
 333        TokenType.PIVOT,
 334        TokenType.PRAGMA,
 335        TokenType.RANGE,
 336        TokenType.RECURSIVE,
 337        TokenType.REFERENCES,
 338        TokenType.REFRESH,
 339        TokenType.REPLACE,
 340        TokenType.RIGHT,
 341        TokenType.ROW,
 342        TokenType.ROWS,
 343        TokenType.SEMI,
 344        TokenType.SET,
 345        TokenType.SETTINGS,
 346        TokenType.SHOW,
 347        TokenType.TEMPORARY,
 348        TokenType.TOP,
 349        TokenType.TRUE,
 350        TokenType.UNIQUE,
 351        TokenType.UNPIVOT,
 352        TokenType.UPDATE,
 353        TokenType.USE,
 354        TokenType.VOLATILE,
 355        TokenType.WINDOW,
 356        *CREATABLES,
 357        *SUBQUERY_PREDICATES,
 358        *TYPE_TOKENS,
 359        *NO_PAREN_FUNCTIONS,
 360    }
 361
 362    INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
 363
 364    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
 365        TokenType.ANTI,
 366        TokenType.APPLY,
 367        TokenType.ASOF,
 368        TokenType.FULL,
 369        TokenType.LEFT,
 370        TokenType.LOCK,
 371        TokenType.NATURAL,
 372        TokenType.OFFSET,
 373        TokenType.RIGHT,
 374        TokenType.SEMI,
 375        TokenType.WINDOW,
 376    }
 377
 378    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
 379
 380    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
 381
 382    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
 383
 384    FUNC_TOKENS = {
 385        TokenType.COLLATE,
 386        TokenType.COMMAND,
 387        TokenType.CURRENT_DATE,
 388        TokenType.CURRENT_DATETIME,
 389        TokenType.CURRENT_TIMESTAMP,
 390        TokenType.CURRENT_TIME,
 391        TokenType.CURRENT_USER,
 392        TokenType.FILTER,
 393        TokenType.FIRST,
 394        TokenType.FORMAT,
 395        TokenType.GLOB,
 396        TokenType.IDENTIFIER,
 397        TokenType.INDEX,
 398        TokenType.ISNULL,
 399        TokenType.ILIKE,
 400        TokenType.INSERT,
 401        TokenType.LIKE,
 402        TokenType.MERGE,
 403        TokenType.OFFSET,
 404        TokenType.PRIMARY_KEY,
 405        TokenType.RANGE,
 406        TokenType.REPLACE,
 407        TokenType.RLIKE,
 408        TokenType.ROW,
 409        TokenType.UNNEST,
 410        TokenType.VAR,
 411        TokenType.LEFT,
 412        TokenType.RIGHT,
 413        TokenType.DATE,
 414        TokenType.DATETIME,
 415        TokenType.TABLE,
 416        TokenType.TIMESTAMP,
 417        TokenType.TIMESTAMPTZ,
 418        TokenType.WINDOW,
 419        TokenType.XOR,
 420        *TYPE_TOKENS,
 421        *SUBQUERY_PREDICATES,
 422    }
 423
 424    CONJUNCTION = {
 425        TokenType.AND: exp.And,
 426        TokenType.OR: exp.Or,
 427    }
 428
 429    EQUALITY = {
 430        TokenType.COLON_EQ: exp.PropertyEQ,
 431        TokenType.EQ: exp.EQ,
 432        TokenType.NEQ: exp.NEQ,
 433        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
 434    }
 435
 436    COMPARISON = {
 437        TokenType.GT: exp.GT,
 438        TokenType.GTE: exp.GTE,
 439        TokenType.LT: exp.LT,
 440        TokenType.LTE: exp.LTE,
 441    }
 442
 443    BITWISE = {
 444        TokenType.AMP: exp.BitwiseAnd,
 445        TokenType.CARET: exp.BitwiseXor,
 446        TokenType.PIPE: exp.BitwiseOr,
 447    }
 448
 449    TERM = {
 450        TokenType.DASH: exp.Sub,
 451        TokenType.PLUS: exp.Add,
 452        TokenType.MOD: exp.Mod,
 453        TokenType.COLLATE: exp.Collate,
 454    }
 455
 456    FACTOR = {
 457        TokenType.DIV: exp.IntDiv,
 458        TokenType.LR_ARROW: exp.Distance,
 459        TokenType.SLASH: exp.Div,
 460        TokenType.STAR: exp.Mul,
 461    }
 462
 463    EXPONENT: t.Dict[TokenType, t.Type[exp.Expression]] = {}
 464
 465    TIMES = {
 466        TokenType.TIME,
 467        TokenType.TIMETZ,
 468    }
 469
 470    TIMESTAMPS = {
 471        TokenType.TIMESTAMP,
 472        TokenType.TIMESTAMPTZ,
 473        TokenType.TIMESTAMPLTZ,
 474        *TIMES,
 475    }
 476
 477    SET_OPERATIONS = {
 478        TokenType.UNION,
 479        TokenType.INTERSECT,
 480        TokenType.EXCEPT,
 481    }
 482
 483    JOIN_METHODS = {
 484        TokenType.NATURAL,
 485        TokenType.ASOF,
 486    }
 487
 488    JOIN_SIDES = {
 489        TokenType.LEFT,
 490        TokenType.RIGHT,
 491        TokenType.FULL,
 492    }
 493
 494    JOIN_KINDS = {
 495        TokenType.INNER,
 496        TokenType.OUTER,
 497        TokenType.CROSS,
 498        TokenType.SEMI,
 499        TokenType.ANTI,
 500    }
 501
 502    JOIN_HINTS: t.Set[str] = set()
 503
 504    LAMBDAS = {
 505        TokenType.ARROW: lambda self, expressions: self.expression(
 506            exp.Lambda,
 507            this=self._replace_lambda(
 508                self._parse_conjunction(),
 509                {node.name for node in expressions},
 510            ),
 511            expressions=expressions,
 512        ),
 513        TokenType.FARROW: lambda self, expressions: self.expression(
 514            exp.Kwarg,
 515            this=exp.var(expressions[0].name),
 516            expression=self._parse_conjunction(),
 517        ),
 518    }
 519
 520    COLUMN_OPERATORS = {
 521        TokenType.DOT: None,
 522        TokenType.DCOLON: lambda self, this, to: self.expression(
 523            exp.Cast if self.STRICT_CAST else exp.TryCast,
 524            this=this,
 525            to=to,
 526        ),
 527        TokenType.ARROW: lambda self, this, path: self.expression(
 528            exp.JSONExtract,
 529            this=this,
 530            expression=path,
 531        ),
 532        TokenType.DARROW: lambda self, this, path: self.expression(
 533            exp.JSONExtractScalar,
 534            this=this,
 535            expression=path,
 536        ),
 537        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
 538            exp.JSONBExtract,
 539            this=this,
 540            expression=path,
 541        ),
 542        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
 543            exp.JSONBExtractScalar,
 544            this=this,
 545            expression=path,
 546        ),
 547        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
 548            exp.JSONBContains,
 549            this=this,
 550            expression=key,
 551        ),
 552    }
 553
 554    EXPRESSION_PARSERS = {
 555        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
 556        exp.Column: lambda self: self._parse_column(),
 557        exp.Condition: lambda self: self._parse_conjunction(),
 558        exp.DataType: lambda self: self._parse_types(allow_identifiers=False),
 559        exp.Expression: lambda self: self._parse_statement(),
 560        exp.From: lambda self: self._parse_from(),
 561        exp.Group: lambda self: self._parse_group(),
 562        exp.Having: lambda self: self._parse_having(),
 563        exp.Identifier: lambda self: self._parse_id_var(),
 564        exp.Join: lambda self: self._parse_join(),
 565        exp.Lambda: lambda self: self._parse_lambda(),
 566        exp.Lateral: lambda self: self._parse_lateral(),
 567        exp.Limit: lambda self: self._parse_limit(),
 568        exp.Offset: lambda self: self._parse_offset(),
 569        exp.Order: lambda self: self._parse_order(),
 570        exp.Ordered: lambda self: self._parse_ordered(),
 571        exp.Properties: lambda self: self._parse_properties(),
 572        exp.Qualify: lambda self: self._parse_qualify(),
 573        exp.Returning: lambda self: self._parse_returning(),
 574        exp.Sort: lambda self: self._parse_sort(exp.Sort, TokenType.SORT_BY),
 575        exp.Table: lambda self: self._parse_table_parts(),
 576        exp.TableAlias: lambda self: self._parse_table_alias(),
 577        exp.When: lambda self: seq_get(self._parse_when_matched(), 0),
 578        exp.Where: lambda self: self._parse_where(),
 579        exp.Window: lambda self: self._parse_named_window(),
 580        exp.With: lambda self: self._parse_with(),
 581        "JOIN_TYPE": lambda self: self._parse_join_parts(),
 582    }
 583
 584    STATEMENT_PARSERS = {
 585        TokenType.ALTER: lambda self: self._parse_alter(),
 586        TokenType.BEGIN: lambda self: self._parse_transaction(),
 587        TokenType.CACHE: lambda self: self._parse_cache(),
 588        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
 589        TokenType.COMMENT: lambda self: self._parse_comment(),
 590        TokenType.CREATE: lambda self: self._parse_create(),
 591        TokenType.DELETE: lambda self: self._parse_delete(),
 592        TokenType.DESC: lambda self: self._parse_describe(),
 593        TokenType.DESCRIBE: lambda self: self._parse_describe(),
 594        TokenType.DROP: lambda self: self._parse_drop(),
 595        TokenType.INSERT: lambda self: self._parse_insert(),
 596        TokenType.KILL: lambda self: self._parse_kill(),
 597        TokenType.LOAD: lambda self: self._parse_load(),
 598        TokenType.MERGE: lambda self: self._parse_merge(),
 599        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
 600        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
 601        TokenType.REFRESH: lambda self: self._parse_refresh(),
 602        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
 603        TokenType.SET: lambda self: self._parse_set(),
 604        TokenType.UNCACHE: lambda self: self._parse_uncache(),
 605        TokenType.UPDATE: lambda self: self._parse_update(),
 606        TokenType.USE: lambda self: self.expression(
 607            exp.Use,
 608            kind=self._match_texts(("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA"))
 609            and exp.var(self._prev.text),
 610            this=self._parse_table(schema=False),
 611        ),
 612    }
 613
 614    UNARY_PARSERS = {
 615        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
 616        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
 617        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
 618        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
 619    }
 620
 621    PRIMARY_PARSERS = {
 622        TokenType.STRING: lambda self, token: self.expression(
 623            exp.Literal, this=token.text, is_string=True
 624        ),
 625        TokenType.NUMBER: lambda self, token: self.expression(
 626            exp.Literal, this=token.text, is_string=False
 627        ),
 628        TokenType.STAR: lambda self, _: self.expression(
 629            exp.Star, **{"except": self._parse_except(), "replace": self._parse_replace()}
 630        ),
 631        TokenType.NULL: lambda self, _: self.expression(exp.Null),
 632        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
 633        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
 634        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
 635        TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text),
 636        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
 637        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
 638        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
 639            exp.National, this=token.text
 640        ),
 641        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
 642        TokenType.HEREDOC_STRING: lambda self, token: self.expression(
 643            exp.RawString, this=token.text
 644        ),
 645        TokenType.UNICODE_STRING: lambda self, token: self.expression(
 646            exp.UnicodeString,
 647            this=token.text,
 648            escape=self._match_text_seq("UESCAPE") and self._parse_string(),
 649        ),
 650        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
 651    }
 652
 653    PLACEHOLDER_PARSERS = {
 654        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
 655        TokenType.PARAMETER: lambda self: self._parse_parameter(),
 656        TokenType.COLON: lambda self: self.expression(exp.Placeholder, this=self._prev.text)
 657        if self._match(TokenType.NUMBER) or self._match_set(self.ID_VAR_TOKENS)
 658        else None,
 659    }
 660
 661    RANGE_PARSERS = {
 662        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
 663        TokenType.GLOB: binary_range_parser(exp.Glob),
 664        TokenType.ILIKE: binary_range_parser(exp.ILike),
 665        TokenType.IN: lambda self, this: self._parse_in(this),
 666        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
 667        TokenType.IS: lambda self, this: self._parse_is(this),
 668        TokenType.LIKE: binary_range_parser(exp.Like),
 669        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
 670        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
 671        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
 672        TokenType.FOR: lambda self, this: self._parse_comprehension(this),
 673    }
 674
 675    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
 676        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
 677        "AUTO": lambda self: self._parse_auto_property(),
 678        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
 679        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
 680        "CHARSET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 681        "CHARACTER SET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 682        "CHECKSUM": lambda self: self._parse_checksum(),
 683        "CLUSTER BY": lambda self: self._parse_cluster(),
 684        "CLUSTERED": lambda self: self._parse_clustered_by(),
 685        "COLLATE": lambda self, **kwargs: self._parse_property_assignment(
 686            exp.CollateProperty, **kwargs
 687        ),
 688        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
 689        "CONTAINS": lambda self: self._parse_contains_property(),
 690        "COPY": lambda self: self._parse_copy_property(),
 691        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
 692        "DEFINER": lambda self: self._parse_definer(),
 693        "DETERMINISTIC": lambda self: self.expression(
 694            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 695        ),
 696        "DISTKEY": lambda self: self._parse_distkey(),
 697        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
 698        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
 699        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
 700        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
 701        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
 702        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 703        "FREESPACE": lambda self: self._parse_freespace(),
 704        "HEAP": lambda self: self.expression(exp.HeapProperty),
 705        "IMMUTABLE": lambda self: self.expression(
 706            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 707        ),
 708        "INPUT": lambda self: self.expression(exp.InputModelProperty, this=self._parse_schema()),
 709        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
 710        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
 711        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
 712        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
 713        "LIKE": lambda self: self._parse_create_like(),
 714        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
 715        "LOCK": lambda self: self._parse_locking(),
 716        "LOCKING": lambda self: self._parse_locking(),
 717        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
 718        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
 719        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
 720        "MODIFIES": lambda self: self._parse_modifies_property(),
 721        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
 722        "NO": lambda self: self._parse_no_property(),
 723        "ON": lambda self: self._parse_on_property(),
 724        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
 725        "OUTPUT": lambda self: self.expression(exp.OutputModelProperty, this=self._parse_schema()),
 726        "PARTITION": lambda self: self._parse_partitioned_of(),
 727        "PARTITION BY": lambda self: self._parse_partitioned_by(),
 728        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
 729        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
 730        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
 731        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
 732        "READS": lambda self: self._parse_reads_property(),
 733        "REMOTE": lambda self: self._parse_remote_with_connection(),
 734        "RETURNS": lambda self: self._parse_returns(),
 735        "ROW": lambda self: self._parse_row(),
 736        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
 737        "SAMPLE": lambda self: self.expression(
 738            exp.SampleProperty, this=self._match_text_seq("BY") and self._parse_bitwise()
 739        ),
 740        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
 741        "SETTINGS": lambda self: self.expression(
 742            exp.SettingsProperty, expressions=self._parse_csv(self._parse_set_item)
 743        ),
 744        "SORTKEY": lambda self: self._parse_sortkey(),
 745        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
 746        "STABLE": lambda self: self.expression(
 747            exp.StabilityProperty, this=exp.Literal.string("STABLE")
 748        ),
 749        "STORED": lambda self: self._parse_stored(),
 750        "SYSTEM_VERSIONING": lambda self: self._parse_system_versioning_property(),
 751        "TBLPROPERTIES": lambda self: self._parse_wrapped_csv(self._parse_property),
 752        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
 753        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
 754        "TO": lambda self: self._parse_to_table(),
 755        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
 756        "TRANSFORM": lambda self: self.expression(
 757            exp.TransformModelProperty, expressions=self._parse_wrapped_csv(self._parse_expression)
 758        ),
 759        "TTL": lambda self: self._parse_ttl(),
 760        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 761        "VOLATILE": lambda self: self._parse_volatile_property(),
 762        "WITH": lambda self: self._parse_with_property(),
 763    }
 764
 765    CONSTRAINT_PARSERS = {
 766        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
 767        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
 768        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
 769        "CHARACTER SET": lambda self: self.expression(
 770            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
 771        ),
 772        "CHECK": lambda self: self.expression(
 773            exp.CheckColumnConstraint, this=self._parse_wrapped(self._parse_conjunction)
 774        ),
 775        "COLLATE": lambda self: self.expression(
 776            exp.CollateColumnConstraint, this=self._parse_var()
 777        ),
 778        "COMMENT": lambda self: self.expression(
 779            exp.CommentColumnConstraint, this=self._parse_string()
 780        ),
 781        "COMPRESS": lambda self: self._parse_compress(),
 782        "CLUSTERED": lambda self: self.expression(
 783            exp.ClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
 784        ),
 785        "NONCLUSTERED": lambda self: self.expression(
 786            exp.NonClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
 787        ),
 788        "DEFAULT": lambda self: self.expression(
 789            exp.DefaultColumnConstraint, this=self._parse_bitwise()
 790        ),
 791        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
 792        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
 793        "FORMAT": lambda self: self.expression(
 794            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
 795        ),
 796        "GENERATED": lambda self: self._parse_generated_as_identity(),
 797        "IDENTITY": lambda self: self._parse_auto_increment(),
 798        "INLINE": lambda self: self._parse_inline(),
 799        "LIKE": lambda self: self._parse_create_like(),
 800        "NOT": lambda self: self._parse_not_constraint(),
 801        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
 802        "ON": lambda self: (
 803            self._match(TokenType.UPDATE)
 804            and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function())
 805        )
 806        or self.expression(exp.OnProperty, this=self._parse_id_var()),
 807        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
 808        "PERIOD": lambda self: self._parse_period_for_system_time(),
 809        "PRIMARY KEY": lambda self: self._parse_primary_key(),
 810        "REFERENCES": lambda self: self._parse_references(match=False),
 811        "TITLE": lambda self: self.expression(
 812            exp.TitleColumnConstraint, this=self._parse_var_or_string()
 813        ),
 814        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
 815        "UNIQUE": lambda self: self._parse_unique(),
 816        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
 817        "WITH": lambda self: self.expression(
 818            exp.Properties, expressions=self._parse_wrapped_csv(self._parse_property)
 819        ),
 820    }
 821
 822    ALTER_PARSERS = {
 823        "ADD": lambda self: self._parse_alter_table_add(),
 824        "ALTER": lambda self: self._parse_alter_table_alter(),
 825        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
 826        "DROP": lambda self: self._parse_alter_table_drop(),
 827        "RENAME": lambda self: self._parse_alter_table_rename(),
 828    }
 829
 830    SCHEMA_UNNAMED_CONSTRAINTS = {"CHECK", "FOREIGN KEY", "LIKE", "PRIMARY KEY", "UNIQUE", "PERIOD"}
 831
 832    NO_PAREN_FUNCTION_PARSERS = {
 833        "ANY": lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
 834        "CASE": lambda self: self._parse_case(),
 835        "IF": lambda self: self._parse_if(),
 836        "NEXT": lambda self: self._parse_next_value_for(),
 837    }
 838
 839    INVALID_FUNC_NAME_TOKENS = {
 840        TokenType.IDENTIFIER,
 841        TokenType.STRING,
 842    }
 843
 844    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
 845
 846    FUNCTION_PARSERS = {
 847        "ANY_VALUE": lambda self: self._parse_any_value(),
 848        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
 849        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
 850        "DECODE": lambda self: self._parse_decode(),
 851        "EXTRACT": lambda self: self._parse_extract(),
 852        "JSON_OBJECT": lambda self: self._parse_json_object(),
 853        "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
 854        "JSON_TABLE": lambda self: self._parse_json_table(),
 855        "MATCH": lambda self: self._parse_match_against(),
 856        "OPENJSON": lambda self: self._parse_open_json(),
 857        "POSITION": lambda self: self._parse_position(),
 858        "PREDICT": lambda self: self._parse_predict(),
 859        "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
 860        "STRING_AGG": lambda self: self._parse_string_agg(),
 861        "SUBSTRING": lambda self: self._parse_substring(),
 862        "TRIM": lambda self: self._parse_trim(),
 863        "TRY_CAST": lambda self: self._parse_cast(False, safe=True),
 864        "TRY_CONVERT": lambda self: self._parse_convert(False, safe=True),
 865    }
 866
 867    QUERY_MODIFIER_PARSERS = {
 868        TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
 869        TokenType.WHERE: lambda self: ("where", self._parse_where()),
 870        TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
 871        TokenType.HAVING: lambda self: ("having", self._parse_having()),
 872        TokenType.QUALIFY: lambda self: ("qualify", self._parse_qualify()),
 873        TokenType.WINDOW: lambda self: ("windows", self._parse_window_clause()),
 874        TokenType.ORDER_BY: lambda self: ("order", self._parse_order()),
 875        TokenType.LIMIT: lambda self: ("limit", self._parse_limit()),
 876        TokenType.FETCH: lambda self: ("limit", self._parse_limit()),
 877        TokenType.OFFSET: lambda self: ("offset", self._parse_offset()),
 878        TokenType.FOR: lambda self: ("locks", self._parse_locks()),
 879        TokenType.LOCK: lambda self: ("locks", self._parse_locks()),
 880        TokenType.TABLE_SAMPLE: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
 881        TokenType.USING: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
 882        TokenType.CLUSTER_BY: lambda self: (
 883            "cluster",
 884            self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
 885        ),
 886        TokenType.DISTRIBUTE_BY: lambda self: (
 887            "distribute",
 888            self._parse_sort(exp.Distribute, TokenType.DISTRIBUTE_BY),
 889        ),
 890        TokenType.SORT_BY: lambda self: ("sort", self._parse_sort(exp.Sort, TokenType.SORT_BY)),
 891        TokenType.CONNECT_BY: lambda self: ("connect", self._parse_connect(skip_start_token=True)),
 892        TokenType.START_WITH: lambda self: ("connect", self._parse_connect()),
 893    }
 894
 895    SET_PARSERS = {
 896        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
 897        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
 898        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
 899        "TRANSACTION": lambda self: self._parse_set_transaction(),
 900    }
 901
 902    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
 903
 904    TYPE_LITERAL_PARSERS = {
 905        exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
 906    }
 907
 908    MODIFIABLES = (exp.Subquery, exp.Subqueryable, exp.Table)
 909
 910    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
 911
 912    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
 913
 914    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
 915    TRANSACTION_CHARACTERISTICS = {
 916        "ISOLATION LEVEL REPEATABLE READ",
 917        "ISOLATION LEVEL READ COMMITTED",
 918        "ISOLATION LEVEL READ UNCOMMITTED",
 919        "ISOLATION LEVEL SERIALIZABLE",
 920        "READ WRITE",
 921        "READ ONLY",
 922    }
 923
 924    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
 925
 926    CLONE_KEYWORDS = {"CLONE", "COPY"}
 927    HISTORICAL_DATA_KIND = {"TIMESTAMP", "OFFSET", "STATEMENT", "STREAM"}
 928
 929    OPCLASS_FOLLOW_KEYWORDS = {"ASC", "DESC", "NULLS"}
 930    OPTYPE_FOLLOW_TOKENS = {TokenType.COMMA, TokenType.R_PAREN}
 931
 932    TABLE_INDEX_HINT_TOKENS = {TokenType.FORCE, TokenType.IGNORE, TokenType.USE}
 933
 934    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
 935    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
 936    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
 937
 938    JSON_KEY_VALUE_SEPARATOR_TOKENS = {TokenType.COLON, TokenType.COMMA, TokenType.IS}
 939
 940    FETCH_TOKENS = ID_VAR_TOKENS - {TokenType.ROW, TokenType.ROWS, TokenType.PERCENT}
 941
 942    ADD_CONSTRAINT_TOKENS = {TokenType.CONSTRAINT, TokenType.PRIMARY_KEY, TokenType.FOREIGN_KEY}
 943
 944    DISTINCT_TOKENS = {TokenType.DISTINCT}
 945
 946    NULL_TOKENS = {TokenType.NULL}
 947
 948    UNNEST_OFFSET_ALIAS_TOKENS = ID_VAR_TOKENS - SET_OPERATIONS
 949
 950    STRICT_CAST = True
 951
 952    PREFIXED_PIVOT_COLUMNS = False
 953    IDENTIFY_PIVOT_STRINGS = False
 954
 955    LOG_DEFAULTS_TO_LN = False
 956
 957    # Whether or not ADD is present for each column added by ALTER TABLE
 958    ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
 959
 960    # Whether or not the table sample clause expects CSV syntax
 961    TABLESAMPLE_CSV = False
 962
 963    # Whether or not the SET command needs a delimiter (e.g. "=") for assignments
 964    SET_REQUIRES_ASSIGNMENT_DELIMITER = True
 965
 966    # Whether the TRIM function expects the characters to trim as its first argument
 967    TRIM_PATTERN_FIRST = False
 968
 969    # Whether or not string aliases are supported `SELECT COUNT(*) 'count'`
 970    STRING_ALIASES = False
 971
 972    # Whether query modifiers such as LIMIT are attached to the UNION node (vs its right operand)
 973    MODIFIERS_ATTACHED_TO_UNION = True
 974    UNION_MODIFIERS = {"order", "limit", "offset"}
 975
 976    __slots__ = (
 977        "error_level",
 978        "error_message_context",
 979        "max_errors",
 980        "dialect",
 981        "sql",
 982        "errors",
 983        "_tokens",
 984        "_index",
 985        "_curr",
 986        "_next",
 987        "_prev",
 988        "_prev_comments",
 989    )
 990
 991    # Autofilled
 992    SHOW_TRIE: t.Dict = {}
 993    SET_TRIE: t.Dict = {}
 994
 995    def __init__(
 996        self,
 997        error_level: t.Optional[ErrorLevel] = None,
 998        error_message_context: int = 100,
 999        max_errors: int = 3,
1000        dialect: DialectType = None,
1001    ):
1002        from sqlglot.dialects import Dialect
1003
1004        self.error_level = error_level or ErrorLevel.IMMEDIATE
1005        self.error_message_context = error_message_context
1006        self.max_errors = max_errors
1007        self.dialect = Dialect.get_or_raise(dialect)
1008        self.reset()
1009
1010    def reset(self):
1011        self.sql = ""
1012        self.errors = []
1013        self._tokens = []
1014        self._index = 0
1015        self._curr = None
1016        self._next = None
1017        self._prev = None
1018        self._prev_comments = None
1019
1020    def parse(
1021        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1022    ) -> t.List[t.Optional[exp.Expression]]:
1023        """
1024        Parses a list of tokens and returns a list of syntax trees, one tree
1025        per parsed SQL statement.
1026
1027        Args:
1028            raw_tokens: The list of tokens.
1029            sql: The original SQL string, used to produce helpful debug messages.
1030
1031        Returns:
1032            The list of the produced syntax trees.
1033        """
1034        return self._parse(
1035            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1036        )
1037
1038    def parse_into(
1039        self,
1040        expression_types: exp.IntoType,
1041        raw_tokens: t.List[Token],
1042        sql: t.Optional[str] = None,
1043    ) -> t.List[t.Optional[exp.Expression]]:
1044        """
1045        Parses a list of tokens into a given Expression type. If a collection of Expression
1046        types is given instead, this method will try to parse the token list into each one
1047        of them, stopping at the first for which the parsing succeeds.
1048
1049        Args:
1050            expression_types: The expression type(s) to try and parse the token list into.
1051            raw_tokens: The list of tokens.
1052            sql: The original SQL string, used to produce helpful debug messages.
1053
1054        Returns:
1055            The target Expression.
1056        """
1057        errors = []
1058        for expression_type in ensure_list(expression_types):
1059            parser = self.EXPRESSION_PARSERS.get(expression_type)
1060            if not parser:
1061                raise TypeError(f"No parser registered for {expression_type}")
1062
1063            try:
1064                return self._parse(parser, raw_tokens, sql)
1065            except ParseError as e:
1066                e.errors[0]["into_expression"] = expression_type
1067                errors.append(e)
1068
1069        raise ParseError(
1070            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1071            errors=merge_errors(errors),
1072        ) from errors[-1]
1073
1074    def _parse(
1075        self,
1076        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
1077        raw_tokens: t.List[Token],
1078        sql: t.Optional[str] = None,
1079    ) -> t.List[t.Optional[exp.Expression]]:
1080        self.reset()
1081        self.sql = sql or ""
1082
1083        total = len(raw_tokens)
1084        chunks: t.List[t.List[Token]] = [[]]
1085
1086        for i, token in enumerate(raw_tokens):
1087            if token.token_type == TokenType.SEMICOLON:
1088                if i < total - 1:
1089                    chunks.append([])
1090            else:
1091                chunks[-1].append(token)
1092
1093        expressions = []
1094
1095        for tokens in chunks:
1096            self._index = -1
1097            self._tokens = tokens
1098            self._advance()
1099
1100            expressions.append(parse_method(self))
1101
1102            if self._index < len(self._tokens):
1103                self.raise_error("Invalid expression / Unexpected token")
1104
1105            self.check_errors()
1106
1107        return expressions
1108
1109    def check_errors(self) -> None:
1110        """Logs or raises any found errors, depending on the chosen error level setting."""
1111        if self.error_level == ErrorLevel.WARN:
1112            for error in self.errors:
1113                logger.error(str(error))
1114        elif self.error_level == ErrorLevel.RAISE and self.errors:
1115            raise ParseError(
1116                concat_messages(self.errors, self.max_errors),
1117                errors=merge_errors(self.errors),
1118            )
1119
1120    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1121        """
1122        Appends an error in the list of recorded errors or raises it, depending on the chosen
1123        error level setting.
1124        """
1125        token = token or self._curr or self._prev or Token.string("")
1126        start = token.start
1127        end = token.end + 1
1128        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1129        highlight = self.sql[start:end]
1130        end_context = self.sql[end : end + self.error_message_context]
1131
1132        error = ParseError.new(
1133            f"{message}. Line {token.line}, Col: {token.col}.\n"
1134            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1135            description=message,
1136            line=token.line,
1137            col=token.col,
1138            start_context=start_context,
1139            highlight=highlight,
1140            end_context=end_context,
1141        )
1142
1143        if self.error_level == ErrorLevel.IMMEDIATE:
1144            raise error
1145
1146        self.errors.append(error)
1147
1148    def expression(
1149        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1150    ) -> E:
1151        """
1152        Creates a new, validated Expression.
1153
1154        Args:
1155            exp_class: The expression class to instantiate.
1156            comments: An optional list of comments to attach to the expression.
1157            kwargs: The arguments to set for the expression along with their respective values.
1158
1159        Returns:
1160            The target expression.
1161        """
1162        instance = exp_class(**kwargs)
1163        instance.add_comments(comments) if comments else self._add_comments(instance)
1164        return self.validate_expression(instance)
1165
1166    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
1167        if expression and self._prev_comments:
1168            expression.add_comments(self._prev_comments)
1169            self._prev_comments = None
1170
1171    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1172        """
1173        Validates an Expression, making sure that all its mandatory arguments are set.
1174
1175        Args:
1176            expression: The expression to validate.
1177            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1178
1179        Returns:
1180            The validated expression.
1181        """
1182        if self.error_level != ErrorLevel.IGNORE:
1183            for error_message in expression.error_messages(args):
1184                self.raise_error(error_message)
1185
1186        return expression
1187
1188    def _find_sql(self, start: Token, end: Token) -> str:
1189        return self.sql[start.start : end.end + 1]
1190
1191    def _is_connected(self) -> bool:
1192        return self._prev and self._curr and self._prev.end + 1 == self._curr.start
1193
1194    def _advance(self, times: int = 1) -> None:
1195        self._index += times
1196        self._curr = seq_get(self._tokens, self._index)
1197        self._next = seq_get(self._tokens, self._index + 1)
1198
1199        if self._index > 0:
1200            self._prev = self._tokens[self._index - 1]
1201            self._prev_comments = self._prev.comments
1202        else:
1203            self._prev = None
1204            self._prev_comments = None
1205
1206    def _retreat(self, index: int) -> None:
1207        if index != self._index:
1208            self._advance(index - self._index)
1209
1210    def _parse_command(self) -> exp.Command:
1211        return self.expression(
1212            exp.Command, this=self._prev.text.upper(), expression=self._parse_string()
1213        )
1214
1215    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
1216        start = self._prev
1217        exists = self._parse_exists() if allow_exists else None
1218
1219        self._match(TokenType.ON)
1220
1221        kind = self._match_set(self.CREATABLES) and self._prev
1222        if not kind:
1223            return self._parse_as_command(start)
1224
1225        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1226            this = self._parse_user_defined_function(kind=kind.token_type)
1227        elif kind.token_type == TokenType.TABLE:
1228            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
1229        elif kind.token_type == TokenType.COLUMN:
1230            this = self._parse_column()
1231        else:
1232            this = self._parse_id_var()
1233
1234        self._match(TokenType.IS)
1235
1236        return self.expression(
1237            exp.Comment, this=this, kind=kind.text, expression=self._parse_string(), exists=exists
1238        )
1239
1240    def _parse_to_table(
1241        self,
1242    ) -> exp.ToTableProperty:
1243        table = self._parse_table_parts(schema=True)
1244        return self.expression(exp.ToTableProperty, this=table)
1245
1246    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
1247    def _parse_ttl(self) -> exp.Expression:
1248        def _parse_ttl_action() -> t.Optional[exp.Expression]:
1249            this = self._parse_bitwise()
1250
1251            if self._match_text_seq("DELETE"):
1252                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
1253            if self._match_text_seq("RECOMPRESS"):
1254                return self.expression(
1255                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
1256                )
1257            if self._match_text_seq("TO", "DISK"):
1258                return self.expression(
1259                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
1260                )
1261            if self._match_text_seq("TO", "VOLUME"):
1262                return self.expression(
1263                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
1264                )
1265
1266            return this
1267
1268        expressions = self._parse_csv(_parse_ttl_action)
1269        where = self._parse_where()
1270        group = self._parse_group()
1271
1272        aggregates = None
1273        if group and self._match(TokenType.SET):
1274            aggregates = self._parse_csv(self._parse_set_item)
1275
1276        return self.expression(
1277            exp.MergeTreeTTL,
1278            expressions=expressions,
1279            where=where,
1280            group=group,
1281            aggregates=aggregates,
1282        )
1283
1284    def _parse_statement(self) -> t.Optional[exp.Expression]:
1285        if self._curr is None:
1286            return None
1287
1288        if self._match_set(self.STATEMENT_PARSERS):
1289            return self.STATEMENT_PARSERS[self._prev.token_type](self)
1290
1291        if self._match_set(Tokenizer.COMMANDS):
1292            return self._parse_command()
1293
1294        expression = self._parse_expression()
1295        expression = self._parse_set_operations(expression) if expression else self._parse_select()
1296        return self._parse_query_modifiers(expression)
1297
1298    def _parse_drop(self, exists: bool = False) -> exp.Drop | exp.Command:
1299        start = self._prev
1300        temporary = self._match(TokenType.TEMPORARY)
1301        materialized = self._match_text_seq("MATERIALIZED")
1302
1303        kind = self._match_set(self.CREATABLES) and self._prev.text
1304        if not kind:
1305            return self._parse_as_command(start)
1306
1307        return self.expression(
1308            exp.Drop,
1309            comments=start.comments,
1310            exists=exists or self._parse_exists(),
1311            this=self._parse_table(schema=True),
1312            kind=kind,
1313            temporary=temporary,
1314            materialized=materialized,
1315            cascade=self._match_text_seq("CASCADE"),
1316            constraints=self._match_text_seq("CONSTRAINTS"),
1317            purge=self._match_text_seq("PURGE"),
1318        )
1319
1320    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
1321        return (
1322            self._match_text_seq("IF")
1323            and (not not_ or self._match(TokenType.NOT))
1324            and self._match(TokenType.EXISTS)
1325        )
1326
1327    def _parse_create(self) -> exp.Create | exp.Command:
1328        # Note: this can't be None because we've matched a statement parser
1329        start = self._prev
1330        comments = self._prev_comments
1331
1332        replace = start.text.upper() == "REPLACE" or self._match_pair(
1333            TokenType.OR, TokenType.REPLACE
1334        )
1335        unique = self._match(TokenType.UNIQUE)
1336
1337        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
1338            self._advance()
1339
1340        properties = None
1341        create_token = self._match_set(self.CREATABLES) and self._prev
1342
1343        if not create_token:
1344            # exp.Properties.Location.POST_CREATE
1345            properties = self._parse_properties()
1346            create_token = self._match_set(self.CREATABLES) and self._prev
1347
1348            if not properties or not create_token:
1349                return self._parse_as_command(start)
1350
1351        exists = self._parse_exists(not_=True)
1352        this = None
1353        expression: t.Optional[exp.Expression] = None
1354        indexes = None
1355        no_schema_binding = None
1356        begin = None
1357        end = None
1358        clone = None
1359
1360        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
1361            nonlocal properties
1362            if properties and temp_props:
1363                properties.expressions.extend(temp_props.expressions)
1364            elif temp_props:
1365                properties = temp_props
1366
1367        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1368            this = self._parse_user_defined_function(kind=create_token.token_type)
1369
1370            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
1371            extend_props(self._parse_properties())
1372
1373            expression = self._match(TokenType.ALIAS) and self._parse_heredoc()
1374
1375            if not expression:
1376                if self._match(TokenType.COMMAND):
1377                    expression = self._parse_as_command(self._prev)
1378                else:
1379                    begin = self._match(TokenType.BEGIN)
1380                    return_ = self._match_text_seq("RETURN")
1381
1382                    if self._match(TokenType.STRING, advance=False):
1383                        # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
1384                        # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
1385                        expression = self._parse_string()
1386                        extend_props(self._parse_properties())
1387                    else:
1388                        expression = self._parse_statement()
1389
1390                    end = self._match_text_seq("END")
1391
1392                    if return_:
1393                        expression = self.expression(exp.Return, this=expression)
1394        elif create_token.token_type == TokenType.INDEX:
1395            this = self._parse_index(index=self._parse_id_var())
1396        elif create_token.token_type in self.DB_CREATABLES:
1397            table_parts = self._parse_table_parts(schema=True)
1398
1399            # exp.Properties.Location.POST_NAME
1400            self._match(TokenType.COMMA)
1401            extend_props(self._parse_properties(before=True))
1402
1403            this = self._parse_schema(this=table_parts)
1404
1405            # exp.Properties.Location.POST_SCHEMA and POST_WITH
1406            extend_props(self._parse_properties())
1407
1408            self._match(TokenType.ALIAS)
1409            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
1410                # exp.Properties.Location.POST_ALIAS
1411                extend_props(self._parse_properties())
1412
1413            expression = self._parse_ddl_select()
1414
1415            if create_token.token_type == TokenType.TABLE:
1416                # exp.Properties.Location.POST_EXPRESSION
1417                extend_props(self._parse_properties())
1418
1419                indexes = []
1420                while True:
1421                    index = self._parse_index()
1422
1423                    # exp.Properties.Location.POST_INDEX
1424                    extend_props(self._parse_properties())
1425
1426                    if not index:
1427                        break
1428                    else:
1429                        self._match(TokenType.COMMA)
1430                        indexes.append(index)
1431            elif create_token.token_type == TokenType.VIEW:
1432                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
1433                    no_schema_binding = True
1434
1435            shallow = self._match_text_seq("SHALLOW")
1436
1437            if self._match_texts(self.CLONE_KEYWORDS):
1438                copy = self._prev.text.lower() == "copy"
1439                clone = self.expression(
1440                    exp.Clone, this=self._parse_table(schema=True), shallow=shallow, copy=copy
1441                )
1442
1443        return self.expression(
1444            exp.Create,
1445            comments=comments,
1446            this=this,
1447            kind=create_token.text.upper(),
1448            replace=replace,
1449            unique=unique,
1450            expression=expression,
1451            exists=exists,
1452            properties=properties,
1453            indexes=indexes,
1454            no_schema_binding=no_schema_binding,
1455            begin=begin,
1456            end=end,
1457            clone=clone,
1458        )
1459
1460    def _parse_property_before(self) -> t.Optional[exp.Expression]:
1461        # only used for teradata currently
1462        self._match(TokenType.COMMA)
1463
1464        kwargs = {
1465            "no": self._match_text_seq("NO"),
1466            "dual": self._match_text_seq("DUAL"),
1467            "before": self._match_text_seq("BEFORE"),
1468            "default": self._match_text_seq("DEFAULT"),
1469            "local": (self._match_text_seq("LOCAL") and "LOCAL")
1470            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
1471            "after": self._match_text_seq("AFTER"),
1472            "minimum": self._match_texts(("MIN", "MINIMUM")),
1473            "maximum": self._match_texts(("MAX", "MAXIMUM")),
1474        }
1475
1476        if self._match_texts(self.PROPERTY_PARSERS):
1477            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
1478            try:
1479                return parser(self, **{k: v for k, v in kwargs.items() if v})
1480            except TypeError:
1481                self.raise_error(f"Cannot parse property '{self._prev.text}'")
1482
1483        return None
1484
1485    def _parse_property(self) -> t.Optional[exp.Expression]:
1486        if self._match_texts(self.PROPERTY_PARSERS):
1487            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
1488
1489        if self._match(TokenType.DEFAULT) and self._match_texts(self.PROPERTY_PARSERS):
1490            return self.PROPERTY_PARSERS[self._prev.text.upper()](self, default=True)
1491
1492        if self._match_text_seq("COMPOUND", "SORTKEY"):
1493            return self._parse_sortkey(compound=True)
1494
1495        if self._match_text_seq("SQL", "SECURITY"):
1496            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
1497
1498        index = self._index
1499        key = self._parse_column()
1500
1501        if not self._match(TokenType.EQ):
1502            self._retreat(index)
1503            return None
1504
1505        return self.expression(
1506            exp.Property,
1507            this=key.to_dot() if isinstance(key, exp.Column) else key,
1508            value=self._parse_column() or self._parse_var(any_token=True),
1509        )
1510
1511    def _parse_stored(self) -> exp.FileFormatProperty:
1512        self._match(TokenType.ALIAS)
1513
1514        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
1515        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
1516
1517        return self.expression(
1518            exp.FileFormatProperty,
1519            this=self.expression(
1520                exp.InputOutputFormat, input_format=input_format, output_format=output_format
1521            )
1522            if input_format or output_format
1523            else self._parse_var_or_string() or self._parse_number() or self._parse_id_var(),
1524        )
1525
1526    def _parse_property_assignment(self, exp_class: t.Type[E], **kwargs: t.Any) -> E:
1527        self._match(TokenType.EQ)
1528        self._match(TokenType.ALIAS)
1529        return self.expression(exp_class, this=self._parse_field(), **kwargs)
1530
1531    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
1532        properties = []
1533        while True:
1534            if before:
1535                prop = self._parse_property_before()
1536            else:
1537                prop = self._parse_property()
1538
1539            if not prop:
1540                break
1541            for p in ensure_list(prop):
1542                properties.append(p)
1543
1544        if properties:
1545            return self.expression(exp.Properties, expressions=properties)
1546
1547        return None
1548
1549    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
1550        return self.expression(
1551            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
1552        )
1553
1554    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
1555        if self._index >= 2:
1556            pre_volatile_token = self._tokens[self._index - 2]
1557        else:
1558            pre_volatile_token = None
1559
1560        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
1561            return exp.VolatileProperty()
1562
1563        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
1564
1565    def _parse_system_versioning_property(self) -> exp.WithSystemVersioningProperty:
1566        self._match_pair(TokenType.EQ, TokenType.ON)
1567
1568        prop = self.expression(exp.WithSystemVersioningProperty)
1569        if self._match(TokenType.L_PAREN):
1570            self._match_text_seq("HISTORY_TABLE", "=")
1571            prop.set("this", self._parse_table_parts())
1572
1573            if self._match(TokenType.COMMA):
1574                self._match_text_seq("DATA_CONSISTENCY_CHECK", "=")
1575                prop.set("expression", self._advance_any() and self._prev.text.upper())
1576
1577            self._match_r_paren()
1578
1579        return prop
1580
1581    def _parse_with_property(
1582        self,
1583    ) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
1584        if self._match(TokenType.L_PAREN, advance=False):
1585            return self._parse_wrapped_csv(self._parse_property)
1586
1587        if self._match_text_seq("JOURNAL"):
1588            return self._parse_withjournaltable()
1589
1590        if self._match_text_seq("DATA"):
1591            return self._parse_withdata(no=False)
1592        elif self._match_text_seq("NO", "DATA"):
1593            return self._parse_withdata(no=True)
1594
1595        if not self._next:
1596            return None
1597
1598        return self._parse_withisolatedloading()
1599
1600    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
1601    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
1602        self._match(TokenType.EQ)
1603
1604        user = self._parse_id_var()
1605        self._match(TokenType.PARAMETER)
1606        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
1607
1608        if not user or not host:
1609            return None
1610
1611        return exp.DefinerProperty(this=f"{user}@{host}")
1612
1613    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
1614        self._match(TokenType.TABLE)
1615        self._match(TokenType.EQ)
1616        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
1617
1618    def _parse_log(self, no: bool = False) -> exp.LogProperty:
1619        return self.expression(exp.LogProperty, no=no)
1620
1621    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
1622        return self.expression(exp.JournalProperty, **kwargs)
1623
1624    def _parse_checksum(self) -> exp.ChecksumProperty:
1625        self._match(TokenType.EQ)
1626
1627        on = None
1628        if self._match(TokenType.ON):
1629            on = True
1630        elif self._match_text_seq("OFF"):
1631            on = False
1632
1633        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
1634
1635    def _parse_cluster(self) -> exp.Cluster:
1636        return self.expression(exp.Cluster, expressions=self._parse_csv(self._parse_ordered))
1637
1638    def _parse_clustered_by(self) -> exp.ClusteredByProperty:
1639        self._match_text_seq("BY")
1640
1641        self._match_l_paren()
1642        expressions = self._parse_csv(self._parse_column)
1643        self._match_r_paren()
1644
1645        if self._match_text_seq("SORTED", "BY"):
1646            self._match_l_paren()
1647            sorted_by = self._parse_csv(self._parse_ordered)
1648            self._match_r_paren()
1649        else:
1650            sorted_by = None
1651
1652        self._match(TokenType.INTO)
1653        buckets = self._parse_number()
1654        self._match_text_seq("BUCKETS")
1655
1656        return self.expression(
1657            exp.ClusteredByProperty,
1658            expressions=expressions,
1659            sorted_by=sorted_by,
1660            buckets=buckets,
1661        )
1662
1663    def _parse_copy_property(self) -> t.Optional[exp.CopyGrantsProperty]:
1664        if not self._match_text_seq("GRANTS"):
1665            self._retreat(self._index - 1)
1666            return None
1667
1668        return self.expression(exp.CopyGrantsProperty)
1669
1670    def _parse_freespace(self) -> exp.FreespaceProperty:
1671        self._match(TokenType.EQ)
1672        return self.expression(
1673            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
1674        )
1675
1676    def _parse_mergeblockratio(
1677        self, no: bool = False, default: bool = False
1678    ) -> exp.MergeBlockRatioProperty:
1679        if self._match(TokenType.EQ):
1680            return self.expression(
1681                exp.MergeBlockRatioProperty,
1682                this=self._parse_number(),
1683                percent=self._match(TokenType.PERCENT),
1684            )
1685
1686        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
1687
1688    def _parse_datablocksize(
1689        self,
1690        default: t.Optional[bool] = None,
1691        minimum: t.Optional[bool] = None,
1692        maximum: t.Optional[bool] = None,
1693    ) -> exp.DataBlocksizeProperty:
1694        self._match(TokenType.EQ)
1695        size = self._parse_number()
1696
1697        units = None
1698        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
1699            units = self._prev.text
1700
1701        return self.expression(
1702            exp.DataBlocksizeProperty,
1703            size=size,
1704            units=units,
1705            default=default,
1706            minimum=minimum,
1707            maximum=maximum,
1708        )
1709
1710    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
1711        self._match(TokenType.EQ)
1712        always = self._match_text_seq("ALWAYS")
1713        manual = self._match_text_seq("MANUAL")
1714        never = self._match_text_seq("NEVER")
1715        default = self._match_text_seq("DEFAULT")
1716
1717        autotemp = None
1718        if self._match_text_seq("AUTOTEMP"):
1719            autotemp = self._parse_schema()
1720
1721        return self.expression(
1722            exp.BlockCompressionProperty,
1723            always=always,
1724            manual=manual,
1725            never=never,
1726            default=default,
1727            autotemp=autotemp,
1728        )
1729
1730    def _parse_withisolatedloading(self) -> exp.IsolatedLoadingProperty:
1731        no = self._match_text_seq("NO")
1732        concurrent = self._match_text_seq("CONCURRENT")
1733        self._match_text_seq("ISOLATED", "LOADING")
1734        for_all = self._match_text_seq("FOR", "ALL")
1735        for_insert = self._match_text_seq("FOR", "INSERT")
1736        for_none = self._match_text_seq("FOR", "NONE")
1737        return self.expression(
1738            exp.IsolatedLoadingProperty,
1739            no=no,
1740            concurrent=concurrent,
1741            for_all=for_all,
1742            for_insert=for_insert,
1743            for_none=for_none,
1744        )
1745
1746    def _parse_locking(self) -> exp.LockingProperty:
1747        if self._match(TokenType.TABLE):
1748            kind = "TABLE"
1749        elif self._match(TokenType.VIEW):
1750            kind = "VIEW"
1751        elif self._match(TokenType.ROW):
1752            kind = "ROW"
1753        elif self._match_text_seq("DATABASE"):
1754            kind = "DATABASE"
1755        else:
1756            kind = None
1757
1758        if kind in ("DATABASE", "TABLE", "VIEW"):
1759            this = self._parse_table_parts()
1760        else:
1761            this = None
1762
1763        if self._match(TokenType.FOR):
1764            for_or_in = "FOR"
1765        elif self._match(TokenType.IN):
1766            for_or_in = "IN"
1767        else:
1768            for_or_in = None
1769
1770        if self._match_text_seq("ACCESS"):
1771            lock_type = "ACCESS"
1772        elif self._match_texts(("EXCL", "EXCLUSIVE")):
1773            lock_type = "EXCLUSIVE"
1774        elif self._match_text_seq("SHARE"):
1775            lock_type = "SHARE"
1776        elif self._match_text_seq("READ"):
1777            lock_type = "READ"
1778        elif self._match_text_seq("WRITE"):
1779            lock_type = "WRITE"
1780        elif self._match_text_seq("CHECKSUM"):
1781            lock_type = "CHECKSUM"
1782        else:
1783            lock_type = None
1784
1785        override = self._match_text_seq("OVERRIDE")
1786
1787        return self.expression(
1788            exp.LockingProperty,
1789            this=this,
1790            kind=kind,
1791            for_or_in=for_or_in,
1792            lock_type=lock_type,
1793            override=override,
1794        )
1795
1796    def _parse_partition_by(self) -> t.List[exp.Expression]:
1797        if self._match(TokenType.PARTITION_BY):
1798            return self._parse_csv(self._parse_conjunction)
1799        return []
1800
1801    def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
1802        def _parse_partition_bound_expr() -> t.Optional[exp.Expression]:
1803            if self._match_text_seq("MINVALUE"):
1804                return exp.var("MINVALUE")
1805            if self._match_text_seq("MAXVALUE"):
1806                return exp.var("MAXVALUE")
1807            return self._parse_bitwise()
1808
1809        this: t.Optional[exp.Expression | t.List[exp.Expression]] = None
1810        expression = None
1811        from_expressions = None
1812        to_expressions = None
1813
1814        if self._match(TokenType.IN):
1815            this = self._parse_wrapped_csv(self._parse_bitwise)
1816        elif self._match(TokenType.FROM):
1817            from_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
1818            self._match_text_seq("TO")
1819            to_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
1820        elif self._match_text_seq("WITH", "(", "MODULUS"):
1821            this = self._parse_number()
1822            self._match_text_seq(",", "REMAINDER")
1823            expression = self._parse_number()
1824            self._match_r_paren()
1825        else:
1826            self.raise_error("Failed to parse partition bound spec.")
1827
1828        return self.expression(
1829            exp.PartitionBoundSpec,
1830            this=this,
1831            expression=expression,
1832            from_expressions=from_expressions,
1833            to_expressions=to_expressions,
1834        )
1835
1836    # https://www.postgresql.org/docs/current/sql-createtable.html
1837    def _parse_partitioned_of(self) -> t.Optional[exp.PartitionedOfProperty]:
1838        if not self._match_text_seq("OF"):
1839            self._retreat(self._index - 1)
1840            return None
1841
1842        this = self._parse_table(schema=True)
1843
1844        if self._match(TokenType.DEFAULT):
1845            expression: exp.Var | exp.PartitionBoundSpec = exp.var("DEFAULT")
1846        elif self._match_text_seq("FOR", "VALUES"):
1847            expression = self._parse_partition_bound_spec()
1848        else:
1849            self.raise_error("Expecting either DEFAULT or FOR VALUES clause.")
1850
1851        return self.expression(exp.PartitionedOfProperty, this=this, expression=expression)
1852
1853    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
1854        self._match(TokenType.EQ)
1855        return self.expression(
1856            exp.PartitionedByProperty,
1857            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
1858        )
1859
1860    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
1861        if self._match_text_seq("AND", "STATISTICS"):
1862            statistics = True
1863        elif self._match_text_seq("AND", "NO", "STATISTICS"):
1864            statistics = False
1865        else:
1866            statistics = None
1867
1868        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
1869
1870    def _parse_contains_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
1871        if self._match_text_seq("SQL"):
1872            return self.expression(exp.SqlReadWriteProperty, this="CONTAINS SQL")
1873        return None
1874
1875    def _parse_modifies_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
1876        if self._match_text_seq("SQL", "DATA"):
1877            return self.expression(exp.SqlReadWriteProperty, this="MODIFIES SQL DATA")
1878        return None
1879
1880    def _parse_no_property(self) -> t.Optional[exp.Expression]:
1881        if self._match_text_seq("PRIMARY", "INDEX"):
1882            return exp.NoPrimaryIndexProperty()
1883        if self._match_text_seq("SQL"):
1884            return self.expression(exp.SqlReadWriteProperty, this="NO SQL")
1885        return None
1886
1887    def _parse_on_property(self) -> t.Optional[exp.Expression]:
1888        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
1889            return exp.OnCommitProperty()
1890        if self._match_text_seq("COMMIT", "DELETE", "ROWS"):
1891            return exp.OnCommitProperty(delete=True)
1892        return self.expression(exp.OnProperty, this=self._parse_schema(self._parse_id_var()))
1893
1894    def _parse_reads_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
1895        if self._match_text_seq("SQL", "DATA"):
1896            return self.expression(exp.SqlReadWriteProperty, this="READS SQL DATA")
1897        return None
1898
1899    def _parse_distkey(self) -> exp.DistKeyProperty:
1900        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
1901
1902    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
1903        table = self._parse_table(schema=True)
1904
1905        options = []
1906        while self._match_texts(("INCLUDING", "EXCLUDING")):
1907            this = self._prev.text.upper()
1908
1909            id_var = self._parse_id_var()
1910            if not id_var:
1911                return None
1912
1913            options.append(
1914                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
1915            )
1916
1917        return self.expression(exp.LikeProperty, this=table, expressions=options)
1918
1919    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
1920        return self.expression(
1921            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
1922        )
1923
1924    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
1925        self._match(TokenType.EQ)
1926        return self.expression(
1927            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
1928        )
1929
1930    def _parse_remote_with_connection(self) -> exp.RemoteWithConnectionModelProperty:
1931        self._match_text_seq("WITH", "CONNECTION")
1932        return self.expression(
1933            exp.RemoteWithConnectionModelProperty, this=self._parse_table_parts()
1934        )
1935
1936    def _parse_returns(self) -> exp.ReturnsProperty:
1937        value: t.Optional[exp.Expression]
1938        is_table = self._match(TokenType.TABLE)
1939
1940        if is_table:
1941            if self._match(TokenType.LT):
1942                value = self.expression(
1943                    exp.Schema,
1944                    this="TABLE",
1945                    expressions=self._parse_csv(self._parse_struct_types),
1946                )
1947                if not self._match(TokenType.GT):
1948                    self.raise_error("Expecting >")
1949            else:
1950                value = self._parse_schema(exp.var("TABLE"))
1951        else:
1952            value = self._parse_types()
1953
1954        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table)
1955
1956    def _parse_describe(self) -> exp.Describe:
1957        kind = self._match_set(self.CREATABLES) and self._prev.text
1958        extended = self._match_text_seq("EXTENDED")
1959        this = self._parse_table(schema=True)
1960        properties = self._parse_properties()
1961        expressions = properties.expressions if properties else None
1962        return self.expression(
1963            exp.Describe, this=this, extended=extended, kind=kind, expressions=expressions
1964        )
1965
1966    def _parse_insert(self) -> exp.Insert:
1967        comments = ensure_list(self._prev_comments)
1968        overwrite = self._match(TokenType.OVERWRITE)
1969        ignore = self._match(TokenType.IGNORE)
1970        local = self._match_text_seq("LOCAL")
1971        alternative = None
1972
1973        if self._match_text_seq("DIRECTORY"):
1974            this: t.Optional[exp.Expression] = self.expression(
1975                exp.Directory,
1976                this=self._parse_var_or_string(),
1977                local=local,
1978                row_format=self._parse_row_format(match_row=True),
1979            )
1980        else:
1981            if self._match(TokenType.OR):
1982                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
1983
1984            self._match(TokenType.INTO)
1985            comments += ensure_list(self._prev_comments)
1986            self._match(TokenType.TABLE)
1987            this = self._parse_table(schema=True)
1988
1989        returning = self._parse_returning()
1990
1991        return self.expression(
1992            exp.Insert,
1993            comments=comments,
1994            this=this,
1995            by_name=self._match_text_seq("BY", "NAME"),
1996            exists=self._parse_exists(),
1997            partition=self._parse_partition(),
1998            where=self._match_pair(TokenType.REPLACE, TokenType.WHERE)
1999            and self._parse_conjunction(),
2000            expression=self._parse_ddl_select(),
2001            conflict=self._parse_on_conflict(),
2002            returning=returning or self._parse_returning(),
2003            overwrite=overwrite,
2004            alternative=alternative,
2005            ignore=ignore,
2006        )
2007
2008    def _parse_kill(self) -> exp.Kill:
2009        kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
2010
2011        return self.expression(
2012            exp.Kill,
2013            this=self._parse_primary(),
2014            kind=kind,
2015        )
2016
2017    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
2018        conflict = self._match_text_seq("ON", "CONFLICT")
2019        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
2020
2021        if not conflict and not duplicate:
2022            return None
2023
2024        nothing = None
2025        expressions = None
2026        key = None
2027        constraint = None
2028
2029        if conflict:
2030            if self._match_text_seq("ON", "CONSTRAINT"):
2031                constraint = self._parse_id_var()
2032            else:
2033                key = self._parse_csv(self._parse_value)
2034
2035        self._match_text_seq("DO")
2036        if self._match_text_seq("NOTHING"):
2037            nothing = True
2038        else:
2039            self._match(TokenType.UPDATE)
2040            self._match(TokenType.SET)
2041            expressions = self._parse_csv(self._parse_equality)
2042
2043        return self.expression(
2044            exp.OnConflict,
2045            duplicate=duplicate,
2046            expressions=expressions,
2047            nothing=nothing,
2048            key=key,
2049            constraint=constraint,
2050        )
2051
2052    def _parse_returning(self) -> t.Optional[exp.Returning]:
2053        if not self._match(TokenType.RETURNING):
2054            return None
2055        return self.expression(
2056            exp.Returning,
2057            expressions=self._parse_csv(self._parse_expression),
2058            into=self._match(TokenType.INTO) and self._parse_table_part(),
2059        )
2060
2061    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2062        if not self._match(TokenType.FORMAT):
2063            return None
2064        return self._parse_row_format()
2065
2066    def _parse_row_format(
2067        self, match_row: bool = False
2068    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2069        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
2070            return None
2071
2072        if self._match_text_seq("SERDE"):
2073            this = self._parse_string()
2074
2075            serde_properties = None
2076            if self._match(TokenType.SERDE_PROPERTIES):
2077                serde_properties = self.expression(
2078                    exp.SerdeProperties, expressions=self._parse_wrapped_csv(self._parse_property)
2079                )
2080
2081            return self.expression(
2082                exp.RowFormatSerdeProperty, this=this, serde_properties=serde_properties
2083            )
2084
2085        self._match_text_seq("DELIMITED")
2086
2087        kwargs = {}
2088
2089        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
2090            kwargs["fields"] = self._parse_string()
2091            if self._match_text_seq("ESCAPED", "BY"):
2092                kwargs["escaped"] = self._parse_string()
2093        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
2094            kwargs["collection_items"] = self._parse_string()
2095        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
2096            kwargs["map_keys"] = self._parse_string()
2097        if self._match_text_seq("LINES", "TERMINATED", "BY"):
2098            kwargs["lines"] = self._parse_string()
2099        if self._match_text_seq("NULL", "DEFINED", "AS"):
2100            kwargs["null"] = self._parse_string()
2101
2102        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
2103
2104    def _parse_load(self) -> exp.LoadData | exp.Command:
2105        if self._match_text_seq("DATA"):
2106            local = self._match_text_seq("LOCAL")
2107            self._match_text_seq("INPATH")
2108            inpath = self._parse_string()
2109            overwrite = self._match(TokenType.OVERWRITE)
2110            self._match_pair(TokenType.INTO, TokenType.TABLE)
2111
2112            return self.expression(
2113                exp.LoadData,
2114                this=self._parse_table(schema=True),
2115                local=local,
2116                overwrite=overwrite,
2117                inpath=inpath,
2118                partition=self._parse_partition(),
2119                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
2120                serde=self._match_text_seq("SERDE") and self._parse_string(),
2121            )
2122        return self._parse_as_command(self._prev)
2123
2124    def _parse_delete(self) -> exp.Delete:
2125        # This handles MySQL's "Multiple-Table Syntax"
2126        # https://dev.mysql.com/doc/refman/8.0/en/delete.html
2127        tables = None
2128        comments = self._prev_comments
2129        if not self._match(TokenType.FROM, advance=False):
2130            tables = self._parse_csv(self._parse_table) or None
2131
2132        returning = self._parse_returning()
2133
2134        return self.expression(
2135            exp.Delete,
2136            comments=comments,
2137            tables=tables,
2138            this=self._match(TokenType.FROM) and self._parse_table(joins=True),
2139            using=self._match(TokenType.USING) and self._parse_table(joins=True),
2140            where=self._parse_where(),
2141            returning=returning or self._parse_returning(),
2142            limit=self._parse_limit(),
2143        )
2144
2145    def _parse_update(self) -> exp.Update:
2146        comments = self._prev_comments
2147        this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
2148        expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
2149        returning = self._parse_returning()
2150        return self.expression(
2151            exp.Update,
2152            comments=comments,
2153            **{  # type: ignore
2154                "this": this,
2155                "expressions": expressions,
2156                "from": self._parse_from(joins=True),
2157                "where": self._parse_where(),
2158                "returning": returning or self._parse_returning(),
2159                "order": self._parse_order(),
2160                "limit": self._parse_limit(),
2161            },
2162        )
2163
2164    def _parse_uncache(self) -> exp.Uncache:
2165        if not self._match(TokenType.TABLE):
2166            self.raise_error("Expecting TABLE after UNCACHE")
2167
2168        return self.expression(
2169            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
2170        )
2171
2172    def _parse_cache(self) -> exp.Cache:
2173        lazy = self._match_text_seq("LAZY")
2174        self._match(TokenType.TABLE)
2175        table = self._parse_table(schema=True)
2176
2177        options = []
2178        if self._match_text_seq("OPTIONS"):
2179            self._match_l_paren()
2180            k = self._parse_string()
2181            self._match(TokenType.EQ)
2182            v = self._parse_string()
2183            options = [k, v]
2184            self._match_r_paren()
2185
2186        self._match(TokenType.ALIAS)
2187        return self.expression(
2188            exp.Cache,
2189            this=table,
2190            lazy=lazy,
2191            options=options,
2192            expression=self._parse_select(nested=True),
2193        )
2194
2195    def _parse_partition(self) -> t.Optional[exp.Partition]:
2196        if not self._match(TokenType.PARTITION):
2197            return None
2198
2199        return self.expression(
2200            exp.Partition, expressions=self._parse_wrapped_csv(self._parse_conjunction)
2201        )
2202
2203    def _parse_value(self) -> exp.Tuple:
2204        if self._match(TokenType.L_PAREN):
2205            expressions = self._parse_csv(self._parse_expression)
2206            self._match_r_paren()
2207            return self.expression(exp.Tuple, expressions=expressions)
2208
2209        # In presto we can have VALUES 1, 2 which results in 1 column & 2 rows.
2210        # https://prestodb.io/docs/current/sql/values.html
2211        return self.expression(exp.Tuple, expressions=[self._parse_expression()])
2212
2213    def _parse_projections(self) -> t.List[exp.Expression]:
2214        return self._parse_expressions()
2215
2216    def _parse_select(
2217        self,
2218        nested: bool = False,
2219        table: bool = False,
2220        parse_subquery_alias: bool = True,
2221        parse_set_operation: bool = True,
2222    ) -> t.Optional[exp.Expression]:
2223        cte = self._parse_with()
2224
2225        if cte:
2226            this = self._parse_statement()
2227
2228            if not this:
2229                self.raise_error("Failed to parse any statement following CTE")
2230                return cte
2231
2232            if "with" in this.arg_types:
2233                this.set("with", cte)
2234            else:
2235                self.raise_error(f"{this.key} does not support CTE")
2236                this = cte
2237
2238            return this
2239
2240        # duckdb supports leading with FROM x
2241        from_ = self._parse_from() if self._match(TokenType.FROM, advance=False) else None
2242
2243        if self._match(TokenType.SELECT):
2244            comments = self._prev_comments
2245
2246            hint = self._parse_hint()
2247            all_ = self._match(TokenType.ALL)
2248            distinct = self._match_set(self.DISTINCT_TOKENS)
2249
2250            kind = (
2251                self._match(TokenType.ALIAS)
2252                and self._match_texts(("STRUCT", "VALUE"))
2253                and self._prev.text.upper()
2254            )
2255
2256            if distinct:
2257                distinct = self.expression(
2258                    exp.Distinct,
2259                    on=self._parse_value() if self._match(TokenType.ON) else None,
2260                )
2261
2262            if all_ and distinct:
2263                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
2264
2265            limit = self._parse_limit(top=True)
2266            projections = self._parse_projections()
2267
2268            this = self.expression(
2269                exp.Select,
2270                kind=kind,
2271                hint=hint,
2272                distinct=distinct,
2273                expressions=projections,
2274                limit=limit,
2275            )
2276            this.comments = comments
2277
2278            into = self._parse_into()
2279            if into:
2280                this.set("into", into)
2281
2282            if not from_:
2283                from_ = self._parse_from()
2284
2285            if from_:
2286                this.set("from", from_)
2287
2288            this = self._parse_query_modifiers(this)
2289        elif (table or nested) and self._match(TokenType.L_PAREN):
2290            if self._match(TokenType.PIVOT):
2291                this = self._parse_simplified_pivot()
2292            elif self._match(TokenType.FROM):
2293                this = exp.select("*").from_(
2294                    t.cast(exp.From, self._parse_from(skip_from_token=True))
2295                )
2296            else:
2297                this = (
2298                    self._parse_table()
2299                    if table
2300                    else self._parse_select(nested=True, parse_set_operation=False)
2301                )
2302                this = self._parse_query_modifiers(self._parse_set_operations(this))
2303
2304            self._match_r_paren()
2305
2306            # We return early here so that the UNION isn't attached to the subquery by the
2307            # following call to _parse_set_operations, but instead becomes the parent node
2308            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
2309        elif self._match(TokenType.VALUES):
2310            this = self.expression(
2311                exp.Values,
2312                expressions=self._parse_csv(self._parse_value),
2313                alias=self._parse_table_alias(),
2314            )
2315        elif from_:
2316            this = exp.select("*").from_(from_.this, copy=False)
2317        else:
2318            this = None
2319
2320        if parse_set_operation:
2321            return self._parse_set_operations(this)
2322        return this
2323
2324    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
2325        if not skip_with_token and not self._match(TokenType.WITH):
2326            return None
2327
2328        comments = self._prev_comments
2329        recursive = self._match(TokenType.RECURSIVE)
2330
2331        expressions = []
2332        while True:
2333            expressions.append(self._parse_cte())
2334
2335            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
2336                break
2337            else:
2338                self._match(TokenType.WITH)
2339
2340        return self.expression(
2341            exp.With, comments=comments, expressions=expressions, recursive=recursive
2342        )
2343
2344    def _parse_cte(self) -> exp.CTE:
2345        alias = self._parse_table_alias(self.ID_VAR_TOKENS)
2346        if not alias or not alias.this:
2347            self.raise_error("Expected CTE to have alias")
2348
2349        self._match(TokenType.ALIAS)
2350        return self.expression(
2351            exp.CTE, this=self._parse_wrapped(self._parse_statement), alias=alias
2352        )
2353
2354    def _parse_table_alias(
2355        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
2356    ) -> t.Optional[exp.TableAlias]:
2357        any_token = self._match(TokenType.ALIAS)
2358        alias = (
2359            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
2360            or self._parse_string_as_identifier()
2361        )
2362
2363        index = self._index
2364        if self._match(TokenType.L_PAREN):
2365            columns = self._parse_csv(self._parse_function_parameter)
2366            self._match_r_paren() if columns else self._retreat(index)
2367        else:
2368            columns = None
2369
2370        if not alias and not columns:
2371            return None
2372
2373        return self.expression(exp.TableAlias, this=alias, columns=columns)
2374
2375    def _parse_subquery(
2376        self, this: t.Optional[exp.Expression], parse_alias: bool = True
2377    ) -> t.Optional[exp.Subquery]:
2378        if not this:
2379            return None
2380
2381        return self.expression(
2382            exp.Subquery,
2383            this=this,
2384            pivots=self._parse_pivots(),
2385            alias=self._parse_table_alias() if parse_alias else None,
2386        )
2387
2388    def _parse_query_modifiers(
2389        self, this: t.Optional[exp.Expression]
2390    ) -> t.Optional[exp.Expression]:
2391        if isinstance(this, self.MODIFIABLES):
2392            for join in iter(self._parse_join, None):
2393                this.append("joins", join)
2394            for lateral in iter(self._parse_lateral, None):
2395                this.append("laterals", lateral)
2396
2397            while True:
2398                if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
2399                    parser = self.QUERY_MODIFIER_PARSERS[self._curr.token_type]
2400                    key, expression = parser(self)
2401
2402                    if expression:
2403                        this.set(key, expression)
2404                        if key == "limit":
2405                            offset = expression.args.pop("offset", None)
2406                            if offset:
2407                                this.set("offset", exp.Offset(expression=offset))
2408                        continue
2409                break
2410        return this
2411
2412    def _parse_hint(self) -> t.Optional[exp.Hint]:
2413        if self._match(TokenType.HINT):
2414            hints = []
2415            for hint in iter(lambda: self._parse_csv(self._parse_function), []):
2416                hints.extend(hint)
2417
2418            if not self._match_pair(TokenType.STAR, TokenType.SLASH):
2419                self.raise_error("Expected */ after HINT")
2420
2421            return self.expression(exp.Hint, expressions=hints)
2422
2423        return None
2424
2425    def _parse_into(self) -> t.Optional[exp.Into]:
2426        if not self._match(TokenType.INTO):
2427            return None
2428
2429        temp = self._match(TokenType.TEMPORARY)
2430        unlogged = self._match_text_seq("UNLOGGED")
2431        self._match(TokenType.TABLE)
2432
2433        return self.expression(
2434            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
2435        )
2436
2437    def _parse_from(
2438        self, joins: bool = False, skip_from_token: bool = False
2439    ) -> t.Optional[exp.From]:
2440        if not skip_from_token and not self._match(TokenType.FROM):
2441            return None
2442
2443        return self.expression(
2444            exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
2445        )
2446
2447    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
2448        if not self._match(TokenType.MATCH_RECOGNIZE):
2449            return None
2450
2451        self._match_l_paren()
2452
2453        partition = self._parse_partition_by()
2454        order = self._parse_order()
2455        measures = self._parse_expressions() if self._match_text_seq("MEASURES") else None
2456
2457        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
2458            rows = exp.var("ONE ROW PER MATCH")
2459        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
2460            text = "ALL ROWS PER MATCH"
2461            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
2462                text += f" SHOW EMPTY MATCHES"
2463            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
2464                text += f" OMIT EMPTY MATCHES"
2465            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
2466                text += f" WITH UNMATCHED ROWS"
2467            rows = exp.var(text)
2468        else:
2469            rows = None
2470
2471        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
2472            text = "AFTER MATCH SKIP"
2473            if self._match_text_seq("PAST", "LAST", "ROW"):
2474                text += f" PAST LAST ROW"
2475            elif self._match_text_seq("TO", "NEXT", "ROW"):
2476                text += f" TO NEXT ROW"
2477            elif self._match_text_seq("TO", "FIRST"):
2478                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
2479            elif self._match_text_seq("TO", "LAST"):
2480                text += f" TO LAST {self._advance_any().text}"  # type: ignore
2481            after = exp.var(text)
2482        else:
2483            after = None
2484
2485        if self._match_text_seq("PATTERN"):
2486            self._match_l_paren()
2487
2488            if not self._curr:
2489                self.raise_error("Expecting )", self._curr)
2490
2491            paren = 1
2492            start = self._curr
2493
2494            while self._curr and paren > 0:
2495                if self._curr.token_type == TokenType.L_PAREN:
2496                    paren += 1
2497                if self._curr.token_type == TokenType.R_PAREN:
2498                    paren -= 1
2499
2500                end = self._prev
2501                self._advance()
2502
2503            if paren > 0:
2504                self.raise_error("Expecting )", self._curr)
2505
2506            pattern = exp.var(self._find_sql(start, end))
2507        else:
2508            pattern = None
2509
2510        define = (
2511            self._parse_csv(self._parse_name_as_expression)
2512            if self._match_text_seq("DEFINE")
2513            else None
2514        )
2515
2516        self._match_r_paren()
2517
2518        return self.expression(
2519            exp.MatchRecognize,
2520            partition_by=partition,
2521            order=order,
2522            measures=measures,
2523            rows=rows,
2524            after=after,
2525            pattern=pattern,
2526            define=define,
2527            alias=self._parse_table_alias(),
2528        )
2529
2530    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
2531        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
2532        if not cross_apply and self._match_pair(TokenType.OUTER, TokenType.APPLY):
2533            cross_apply = False
2534
2535        if cross_apply is not None:
2536            this = self._parse_select(table=True)
2537            view = None
2538            outer = None
2539        elif self._match(TokenType.LATERAL):
2540            this = self._parse_select(table=True)
2541            view = self._match(TokenType.VIEW)
2542            outer = self._match(TokenType.OUTER)
2543        else:
2544            return None
2545
2546        if not this:
2547            this = (
2548                self._parse_unnest()
2549                or self._parse_function()
2550                or self._parse_id_var(any_token=False)
2551            )
2552
2553            while self._match(TokenType.DOT):
2554                this = exp.Dot(
2555                    this=this,
2556                    expression=self._parse_function() or self._parse_id_var(any_token=False),
2557                )
2558
2559        if view:
2560            table = self._parse_id_var(any_token=False)
2561            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
2562            table_alias: t.Optional[exp.TableAlias] = self.expression(
2563                exp.TableAlias, this=table, columns=columns
2564            )
2565        elif isinstance(this, (exp.Subquery, exp.Unnest)) and this.alias:
2566            # We move the alias from the lateral's child node to the lateral itself
2567            table_alias = this.args["alias"].pop()
2568        else:
2569            table_alias = self._parse_table_alias()
2570
2571        return self.expression(
2572            exp.Lateral,
2573            this=this,
2574            view=view,
2575            outer=outer,
2576            alias=table_alias,
2577            cross_apply=cross_apply,
2578        )
2579
2580    def _parse_join_parts(
2581        self,
2582    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
2583        return (
2584            self._match_set(self.JOIN_METHODS) and self._prev,
2585            self._match_set(self.JOIN_SIDES) and self._prev,
2586            self._match_set(self.JOIN_KINDS) and self._prev,
2587        )
2588
2589    def _parse_join(
2590        self, skip_join_token: bool = False, parse_bracket: bool = False
2591    ) -> t.Optional[exp.Join]:
2592        if self._match(TokenType.COMMA):
2593            return self.expression(exp.Join, this=self._parse_table())
2594
2595        index = self._index
2596        method, side, kind = self._parse_join_parts()
2597        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
2598        join = self._match(TokenType.JOIN)
2599
2600        if not skip_join_token and not join:
2601            self._retreat(index)
2602            kind = None
2603            method = None
2604            side = None
2605
2606        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
2607        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
2608
2609        if not skip_join_token and not join and not outer_apply and not cross_apply:
2610            return None
2611
2612        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table(parse_bracket=parse_bracket)}
2613
2614        if method:
2615            kwargs["method"] = method.text
2616        if side:
2617            kwargs["side"] = side.text
2618        if kind:
2619            kwargs["kind"] = kind.text
2620        if hint:
2621            kwargs["hint"] = hint
2622
2623        if self._match(TokenType.ON):
2624            kwargs["on"] = self._parse_conjunction()
2625        elif self._match(TokenType.USING):
2626            kwargs["using"] = self._parse_wrapped_id_vars()
2627        elif not (kind and kind.token_type == TokenType.CROSS):
2628            index = self._index
2629            join = self._parse_join()
2630
2631            if join and self._match(TokenType.ON):
2632                kwargs["on"] = self._parse_conjunction()
2633            elif join and self._match(TokenType.USING):
2634                kwargs["using"] = self._parse_wrapped_id_vars()
2635            else:
2636                join = None
2637                self._retreat(index)
2638
2639            kwargs["this"].set("joins", [join] if join else None)
2640
2641        comments = [c for token in (method, side, kind) if token for c in token.comments]
2642        return self.expression(exp.Join, comments=comments, **kwargs)
2643
2644    def _parse_opclass(self) -> t.Optional[exp.Expression]:
2645        this = self._parse_conjunction()
2646        if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
2647            return this
2648
2649        if not self._match_set(self.OPTYPE_FOLLOW_TOKENS, advance=False):
2650            return self.expression(exp.Opclass, this=this, expression=self._parse_table_parts())
2651
2652        return this
2653
2654    def _parse_index(
2655        self,
2656        index: t.Optional[exp.Expression] = None,
2657    ) -> t.Optional[exp.Index]:
2658        if index:
2659            unique = None
2660            primary = None
2661            amp = None
2662
2663            self._match(TokenType.ON)
2664            self._match(TokenType.TABLE)  # hive
2665            table = self._parse_table_parts(schema=True)
2666        else:
2667            unique = self._match(TokenType.UNIQUE)
2668            primary = self._match_text_seq("PRIMARY")
2669            amp = self._match_text_seq("AMP")
2670
2671            if not self._match(TokenType.INDEX):
2672                return None
2673
2674            index = self._parse_id_var()
2675            table = None
2676
2677        using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
2678
2679        if self._match(TokenType.L_PAREN, advance=False):
2680            columns = self._parse_wrapped_csv(lambda: self._parse_ordered(self._parse_opclass))
2681        else:
2682            columns = None
2683
2684        return self.expression(
2685            exp.Index,
2686            this=index,
2687            table=table,
2688            using=using,
2689            columns=columns,
2690            unique=unique,
2691            primary=primary,
2692            amp=amp,
2693            partition_by=self._parse_partition_by(),
2694            where=self._parse_where(),
2695        )
2696
2697    def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
2698        hints: t.List[exp.Expression] = []
2699        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
2700            # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
2701            hints.append(
2702                self.expression(
2703                    exp.WithTableHint,
2704                    expressions=self._parse_csv(
2705                        lambda: self._parse_function() or self._parse_var(any_token=True)
2706                    ),
2707                )
2708            )
2709            self._match_r_paren()
2710        else:
2711            # https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
2712            while self._match_set(self.TABLE_INDEX_HINT_TOKENS):
2713                hint = exp.IndexTableHint(this=self._prev.text.upper())
2714
2715                self._match_texts(("INDEX", "KEY"))
2716                if self._match(TokenType.FOR):
2717                    hint.set("target", self._advance_any() and self._prev.text.upper())
2718
2719                hint.set("expressions", self._parse_wrapped_id_vars())
2720                hints.append(hint)
2721
2722        return hints or None
2723
2724    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
2725        return (
2726            (not schema and self._parse_function(optional_parens=False))
2727            or self._parse_id_var(any_token=False)
2728            or self._parse_string_as_identifier()
2729            or self._parse_placeholder()
2730        )
2731
2732    def _parse_table_parts(self, schema: bool = False) -> exp.Table:
2733        catalog = None
2734        db = None
2735        table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
2736
2737        while self._match(TokenType.DOT):
2738            if catalog:
2739                # This allows nesting the table in arbitrarily many dot expressions if needed
2740                table = self.expression(
2741                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
2742                )
2743            else:
2744                catalog = db
2745                db = table
2746                table = self._parse_table_part(schema=schema) or ""
2747
2748        if not table:
2749            self.raise_error(f"Expected table name but got {self._curr}")
2750
2751        return self.expression(
2752            exp.Table, this=table, db=db, catalog=catalog, pivots=self._parse_pivots()
2753        )
2754
2755    def _parse_table(
2756        self,
2757        schema: bool = False,
2758        joins: bool = False,
2759        alias_tokens: t.Optional[t.Collection[TokenType]] = None,
2760        parse_bracket: bool = False,
2761    ) -> t.Optional[exp.Expression]:
2762        lateral = self._parse_lateral()
2763        if lateral:
2764            return lateral
2765
2766        unnest = self._parse_unnest()
2767        if unnest:
2768            return unnest
2769
2770        values = self._parse_derived_table_values()
2771        if values:
2772            return values
2773
2774        subquery = self._parse_select(table=True)
2775        if subquery:
2776            if not subquery.args.get("pivots"):
2777                subquery.set("pivots", self._parse_pivots())
2778            return subquery
2779
2780        bracket = parse_bracket and self._parse_bracket(None)
2781        bracket = self.expression(exp.Table, this=bracket) if bracket else None
2782        this = t.cast(
2783            exp.Expression, bracket or self._parse_bracket(self._parse_table_parts(schema=schema))
2784        )
2785
2786        if schema:
2787            return self._parse_schema(this=this)
2788
2789        version = self._parse_version()
2790
2791        if version:
2792            this.set("version", version)
2793
2794        if self.dialect.ALIAS_POST_TABLESAMPLE:
2795            table_sample = self._parse_table_sample()
2796
2797        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
2798        if alias:
2799            this.set("alias", alias)
2800
2801        if isinstance(this, exp.Table) and self._match_text_seq("AT"):
2802            return self.expression(
2803                exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
2804            )
2805
2806        this.set("hints", self._parse_table_hints())
2807
2808        if not this.args.get("pivots"):
2809            this.set("pivots", self._parse_pivots())
2810
2811        if not self.dialect.ALIAS_POST_TABLESAMPLE:
2812            table_sample = self._parse_table_sample()
2813
2814        if table_sample:
2815            table_sample.set("this", this)
2816            this = table_sample
2817
2818        if joins:
2819            for join in iter(self._parse_join, None):
2820                this.append("joins", join)
2821
2822        if self._match_pair(TokenType.WITH, TokenType.ORDINALITY):
2823            this.set("ordinality", True)
2824            this.set("alias", self._parse_table_alias())
2825
2826        return this
2827
2828    def _parse_version(self) -> t.Optional[exp.Version]:
2829        if self._match(TokenType.TIMESTAMP_SNAPSHOT):
2830            this = "TIMESTAMP"
2831        elif self._match(TokenType.VERSION_SNAPSHOT):
2832            this = "VERSION"
2833        else:
2834            return None
2835
2836        if self._match_set((TokenType.FROM, TokenType.BETWEEN)):
2837            kind = self._prev.text.upper()
2838            start = self._parse_bitwise()
2839            self._match_texts(("TO", "AND"))
2840            end = self._parse_bitwise()
2841            expression: t.Optional[exp.Expression] = self.expression(
2842                exp.Tuple, expressions=[start, end]
2843            )
2844        elif self._match_text_seq("CONTAINED", "IN"):
2845            kind = "CONTAINED IN"
2846            expression = self.expression(
2847                exp.Tuple, expressions=self._parse_wrapped_csv(self._parse_bitwise)
2848            )
2849        elif self._match(TokenType.ALL):
2850            kind = "ALL"
2851            expression = None
2852        else:
2853            self._match_text_seq("AS", "OF")
2854            kind = "AS OF"
2855            expression = self._parse_type()
2856
2857        return self.expression(exp.Version, this=this, expression=expression, kind=kind)
2858
2859    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
2860        if not self._match(TokenType.UNNEST):
2861            return None
2862
2863        expressions = self._parse_wrapped_csv(self._parse_equality)
2864        offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
2865
2866        alias = self._parse_table_alias() if with_alias else None
2867
2868        if alias:
2869            if self.dialect.UNNEST_COLUMN_ONLY:
2870                if alias.args.get("columns"):
2871                    self.raise_error("Unexpected extra column alias in unnest.")
2872
2873                alias.set("columns", [alias.this])
2874                alias.set("this", None)
2875
2876            columns = alias.args.get("columns") or []
2877            if offset and len(expressions) < len(columns):
2878                offset = columns.pop()
2879
2880        if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
2881            self._match(TokenType.ALIAS)
2882            offset = self._parse_id_var(
2883                any_token=False, tokens=self.UNNEST_OFFSET_ALIAS_TOKENS
2884            ) or exp.to_identifier("offset")
2885
2886        return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
2887
2888    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
2889        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
2890        if not is_derived and not self._match(TokenType.VALUES):
2891            return None
2892
2893        expressions = self._parse_csv(self._parse_value)
2894        alias = self._parse_table_alias()
2895
2896        if is_derived:
2897            self._match_r_paren()
2898
2899        return self.expression(
2900            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
2901        )
2902
2903    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
2904        if not self._match(TokenType.TABLE_SAMPLE) and not (
2905            as_modifier and self._match_text_seq("USING", "SAMPLE")
2906        ):
2907            return None
2908
2909        bucket_numerator = None
2910        bucket_denominator = None
2911        bucket_field = None
2912        percent = None
2913        size = None
2914        seed = None
2915
2916        method = self._parse_var(tokens=(TokenType.ROW,), upper=True)
2917        matched_l_paren = self._match(TokenType.L_PAREN)
2918
2919        if self.TABLESAMPLE_CSV:
2920            num = None
2921            expressions = self._parse_csv(self._parse_primary)
2922        else:
2923            expressions = None
2924            num = (
2925                self._parse_factor()
2926                if self._match(TokenType.NUMBER, advance=False)
2927                else self._parse_primary() or self._parse_placeholder()
2928            )
2929
2930        if self._match_text_seq("BUCKET"):
2931            bucket_numerator = self._parse_number()
2932            self._match_text_seq("OUT", "OF")
2933            bucket_denominator = bucket_denominator = self._parse_number()
2934            self._match(TokenType.ON)
2935            bucket_field = self._parse_field()
2936        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
2937            percent = num
2938        elif self._match(TokenType.ROWS) or not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
2939            size = num
2940        else:
2941            percent = num
2942
2943        if matched_l_paren:
2944            self._match_r_paren()
2945
2946        if self._match(TokenType.L_PAREN):
2947            method = self._parse_var(upper=True)
2948            seed = self._match(TokenType.COMMA) and self._parse_number()
2949            self._match_r_paren()
2950        elif self._match_texts(("SEED", "REPEATABLE")):
2951            seed = self._parse_wrapped(self._parse_number)
2952
2953        return self.expression(
2954            exp.TableSample,
2955            expressions=expressions,
2956            method=method,
2957            bucket_numerator=bucket_numerator,
2958            bucket_denominator=bucket_denominator,
2959            bucket_field=bucket_field,
2960            percent=percent,
2961            size=size,
2962            seed=seed,
2963        )
2964
2965    def _parse_pivots(self) -> t.Optional[t.List[exp.Pivot]]:
2966        return list(iter(self._parse_pivot, None)) or None
2967
2968    def _parse_joins(self) -> t.Optional[t.List[exp.Join]]:
2969        return list(iter(self._parse_join, None)) or None
2970
2971    # https://duckdb.org/docs/sql/statements/pivot
2972    def _parse_simplified_pivot(self) -> exp.Pivot:
2973        def _parse_on() -> t.Optional[exp.Expression]:
2974            this = self._parse_bitwise()
2975            return self._parse_in(this) if self._match(TokenType.IN) else this
2976
2977        this = self._parse_table()
2978        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
2979        using = self._match(TokenType.USING) and self._parse_csv(
2980            lambda: self._parse_alias(self._parse_function())
2981        )
2982        group = self._parse_group()
2983        return self.expression(
2984            exp.Pivot, this=this, expressions=expressions, using=using, group=group
2985        )
2986
2987    def _parse_pivot_in(self) -> exp.In:
2988        def _parse_aliased_expression() -> t.Optional[exp.Expression]:
2989            this = self._parse_conjunction()
2990
2991            self._match(TokenType.ALIAS)
2992            alias = self._parse_field()
2993            if alias:
2994                return self.expression(exp.PivotAlias, this=this, alias=alias)
2995
2996            return this
2997
2998        value = self._parse_column()
2999
3000        if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
3001            self.raise_error("Expecting IN (")
3002
3003        aliased_expressions = self._parse_csv(_parse_aliased_expression)
3004
3005        self._match_r_paren()
3006        return self.expression(exp.In, this=value, expressions=aliased_expressions)
3007
3008    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
3009        index = self._index
3010        include_nulls = None
3011
3012        if self._match(TokenType.PIVOT):
3013            unpivot = False
3014        elif self._match(TokenType.UNPIVOT):
3015            unpivot = True
3016
3017            # https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
3018            if self._match_text_seq("INCLUDE", "NULLS"):
3019                include_nulls = True
3020            elif self._match_text_seq("EXCLUDE", "NULLS"):
3021                include_nulls = False
3022        else:
3023            return None
3024
3025        expressions = []
3026
3027        if not self._match(TokenType.L_PAREN):
3028            self._retreat(index)
3029            return None
3030
3031        if unpivot:
3032            expressions = self._parse_csv(self._parse_column)
3033        else:
3034            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
3035
3036        if not expressions:
3037            self.raise_error("Failed to parse PIVOT's aggregation list")
3038
3039        if not self._match(TokenType.FOR):
3040            self.raise_error("Expecting FOR")
3041
3042        field = self._parse_pivot_in()
3043
3044        self._match_r_paren()
3045
3046        pivot = self.expression(
3047            exp.Pivot,
3048            expressions=expressions,
3049            field=field,
3050            unpivot=unpivot,
3051            include_nulls=include_nulls,
3052        )
3053
3054        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
3055            pivot.set("alias", self._parse_table_alias())
3056
3057        if not unpivot:
3058            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
3059
3060            columns: t.List[exp.Expression] = []
3061            for fld in pivot.args["field"].expressions:
3062                field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
3063                for name in names:
3064                    if self.PREFIXED_PIVOT_COLUMNS:
3065                        name = f"{name}_{field_name}" if name else field_name
3066                    else:
3067                        name = f"{field_name}_{name}" if name else field_name
3068
3069                    columns.append(exp.to_identifier(name))
3070
3071            pivot.set("columns", columns)
3072
3073        return pivot
3074
3075    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
3076        return [agg.alias for agg in aggregations]
3077
3078    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
3079        if not skip_where_token and not self._match(TokenType.WHERE):
3080            return None
3081
3082        return self.expression(
3083            exp.Where, comments=self._prev_comments, this=self._parse_conjunction()
3084        )
3085
3086    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
3087        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
3088            return None
3089
3090        elements = defaultdict(list)
3091
3092        if self._match(TokenType.ALL):
3093            return self.expression(exp.Group, all=True)
3094
3095        while True:
3096            expressions = self._parse_csv(self._parse_conjunction)
3097            if expressions:
3098                elements["expressions"].extend(expressions)
3099
3100            grouping_sets = self._parse_grouping_sets()
3101            if grouping_sets:
3102                elements["grouping_sets"].extend(grouping_sets)
3103
3104            rollup = None
3105            cube = None
3106            totals = None
3107
3108            index = self._index
3109            with_ = self._match(TokenType.WITH)
3110            if self._match(TokenType.ROLLUP):
3111                rollup = with_ or self._parse_wrapped_csv(self._parse_column)
3112                elements["rollup"].extend(ensure_list(rollup))
3113
3114            if self._match(TokenType.CUBE):
3115                cube = with_ or self._parse_wrapped_csv(self._parse_column)
3116                elements["cube"].extend(ensure_list(cube))
3117
3118            if self._match_text_seq("TOTALS"):
3119                totals = True
3120                elements["totals"] = True  # type: ignore
3121
3122            if not (grouping_sets or rollup or cube or totals):
3123                if with_:
3124                    self._retreat(index)
3125                break
3126
3127        return self.expression(exp.Group, **elements)  # type: ignore
3128
3129    def _parse_grouping_sets(self) -> t.Optional[t.List[exp.Expression]]:
3130        if not self._match(TokenType.GROUPING_SETS):
3131            return None
3132
3133        return self._parse_wrapped_csv(self._parse_grouping_set)
3134
3135    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
3136        if self._match(TokenType.L_PAREN):
3137            grouping_set = self._parse_csv(self._parse_column)
3138            self._match_r_paren()
3139            return self.expression(exp.Tuple, expressions=grouping_set)
3140
3141        return self._parse_column()
3142
3143    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
3144        if not skip_having_token and not self._match(TokenType.HAVING):
3145            return None
3146        return self.expression(exp.Having, this=self._parse_conjunction())
3147
3148    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
3149        if not self._match(TokenType.QUALIFY):
3150            return None
3151        return self.expression(exp.Qualify, this=self._parse_conjunction())
3152
3153    def _parse_connect(self, skip_start_token: bool = False) -> t.Optional[exp.Connect]:
3154        if skip_start_token:
3155            start = None
3156        elif self._match(TokenType.START_WITH):
3157            start = self._parse_conjunction()
3158        else:
3159            return None
3160
3161        self._match(TokenType.CONNECT_BY)
3162        self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
3163            exp.Prior, this=self._parse_bitwise()
3164        )
3165        connect = self._parse_conjunction()
3166        self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
3167
3168        if not start and self._match(TokenType.START_WITH):
3169            start = self._parse_conjunction()
3170
3171        return self.expression(exp.Connect, start=start, connect=connect)
3172
3173    def _parse_name_as_expression(self) -> exp.Alias:
3174        return self.expression(
3175            exp.Alias,
3176            alias=self._parse_id_var(any_token=True),
3177            this=self._match(TokenType.ALIAS) and self._parse_conjunction(),
3178        )
3179
3180    def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
3181        if self._match_text_seq("INTERPOLATE"):
3182            return self._parse_wrapped_csv(self._parse_name_as_expression)
3183        return None
3184
3185    def _parse_order(
3186        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
3187    ) -> t.Optional[exp.Expression]:
3188        siblings = None
3189        if not skip_order_token and not self._match(TokenType.ORDER_BY):
3190            if not self._match(TokenType.ORDER_SIBLINGS_BY):
3191                return this
3192
3193            siblings = True
3194
3195        return self.expression(
3196            exp.Order,
3197            this=this,
3198            expressions=self._parse_csv(self._parse_ordered),
3199            interpolate=self._parse_interpolate(),
3200            siblings=siblings,
3201        )
3202
3203    def _parse_sort(self, exp_class: t.Type[E], token: TokenType) -> t.Optional[E]:
3204        if not self._match(token):
3205            return None
3206        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
3207
3208    def _parse_ordered(self, parse_method: t.Optional[t.Callable] = None) -> exp.Ordered:
3209        this = parse_method() if parse_method else self._parse_conjunction()
3210
3211        asc = self._match(TokenType.ASC)
3212        desc = self._match(TokenType.DESC) or (asc and False)
3213
3214        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
3215        is_nulls_last = self._match_text_seq("NULLS", "LAST")
3216
3217        nulls_first = is_nulls_first or False
3218        explicitly_null_ordered = is_nulls_first or is_nulls_last
3219
3220        if (
3221            not explicitly_null_ordered
3222            and (
3223                (not desc and self.dialect.NULL_ORDERING == "nulls_are_small")
3224                or (desc and self.dialect.NULL_ORDERING != "nulls_are_small")
3225            )
3226            and self.dialect.NULL_ORDERING != "nulls_are_last"
3227        ):
3228            nulls_first = True
3229
3230        if self._match_text_seq("WITH", "FILL"):
3231            with_fill = self.expression(
3232                exp.WithFill,
3233                **{  # type: ignore
3234                    "from": self._match(TokenType.FROM) and self._parse_bitwise(),
3235                    "to": self._match_text_seq("TO") and self._parse_bitwise(),
3236                    "step": self._match_text_seq("STEP") and self._parse_bitwise(),
3237                },
3238            )
3239        else:
3240            with_fill = None
3241
3242        return self.expression(
3243            exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
3244        )
3245
3246    def _parse_limit(
3247        self, this: t.Optional[exp.Expression] = None, top: bool = False
3248    ) -> t.Optional[exp.Expression]:
3249        if self._match(TokenType.TOP if top else TokenType.LIMIT):
3250            comments = self._prev_comments
3251            if top:
3252                limit_paren = self._match(TokenType.L_PAREN)
3253                expression = self._parse_term() if limit_paren else self._parse_number()
3254
3255                if limit_paren:
3256                    self._match_r_paren()
3257            else:
3258                expression = self._parse_term()
3259
3260            if self._match(TokenType.COMMA):
3261                offset = expression
3262                expression = self._parse_term()
3263            else:
3264                offset = None
3265
3266            limit_exp = self.expression(
3267                exp.Limit, this=this, expression=expression, offset=offset, comments=comments
3268            )
3269
3270            return limit_exp
3271
3272        if self._match(TokenType.FETCH):
3273            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
3274            direction = self._prev.text.upper() if direction else "FIRST"
3275
3276            count = self._parse_field(tokens=self.FETCH_TOKENS)
3277            percent = self._match(TokenType.PERCENT)
3278
3279            self._match_set((TokenType.ROW, TokenType.ROWS))
3280
3281            only = self._match_text_seq("ONLY")
3282            with_ties = self._match_text_seq("WITH", "TIES")
3283
3284            if only and with_ties:
3285                self.raise_error("Cannot specify both ONLY and WITH TIES in FETCH clause")
3286
3287            return self.expression(
3288                exp.Fetch,
3289                direction=direction,
3290                count=count,
3291                percent=percent,
3292                with_ties=with_ties,
3293            )
3294
3295        return this
3296
3297    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
3298        if not self._match(TokenType.OFFSET):
3299            return this
3300
3301        count = self._parse_term()
3302        self._match_set((TokenType.ROW, TokenType.ROWS))
3303        return self.expression(exp.Offset, this=this, expression=count)
3304
3305    def _parse_locks(self) -> t.List[exp.Lock]:
3306        locks = []
3307        while True:
3308            if self._match_text_seq("FOR", "UPDATE"):
3309                update = True
3310            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
3311                "LOCK", "IN", "SHARE", "MODE"
3312            ):
3313                update = False
3314            else:
3315                break
3316
3317            expressions = None
3318            if self._match_text_seq("OF"):
3319                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
3320
3321            wait: t.Optional[bool | exp.Expression] = None
3322            if self._match_text_seq("NOWAIT"):
3323                wait = True
3324            elif self._match_text_seq("WAIT"):
3325                wait = self._parse_primary()
3326            elif self._match_text_seq("SKIP", "LOCKED"):
3327                wait = False
3328
3329            locks.append(
3330                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
3331            )
3332
3333        return locks
3334
3335    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3336        while this and self._match_set(self.SET_OPERATIONS):
3337            token_type = self._prev.token_type
3338
3339            if token_type == TokenType.UNION:
3340                operation = exp.Union
3341            elif token_type == TokenType.EXCEPT:
3342                operation = exp.Except
3343            else:
3344                operation = exp.Intersect
3345
3346            comments = self._prev.comments
3347            distinct = self._match(TokenType.DISTINCT) or not self._match(TokenType.ALL)
3348            by_name = self._match_text_seq("BY", "NAME")
3349            expression = self._parse_select(nested=True, parse_set_operation=False)
3350
3351            this = self.expression(
3352                operation,
3353                comments=comments,
3354                this=this,
3355                distinct=distinct,
3356                by_name=by_name,
3357                expression=expression,
3358            )
3359
3360        if isinstance(this, exp.Union) and self.MODIFIERS_ATTACHED_TO_UNION:
3361            expression = this.expression
3362
3363            if expression:
3364                for arg in self.UNION_MODIFIERS:
3365                    expr = expression.args.get(arg)
3366                    if expr:
3367                        this.set(arg, expr.pop())
3368
3369        return this
3370
3371    def _parse_expression(self) -> t.Optional[exp.Expression]:
3372        return self._parse_alias(self._parse_conjunction())
3373
3374    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
3375        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
3376
3377    def _parse_equality(self) -> t.Optional[exp.Expression]:
3378        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
3379
3380    def _parse_comparison(self) -> t.Optional[exp.Expression]:
3381        return self._parse_tokens(self._parse_range, self.COMPARISON)
3382
3383    def _parse_range(self) -> t.Optional[exp.Expression]:
3384        this = self._parse_bitwise()
3385        negate = self._match(TokenType.NOT)
3386
3387        if self._match_set(self.RANGE_PARSERS):
3388            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
3389            if not expression:
3390                return this
3391
3392            this = expression
3393        elif self._match(TokenType.ISNULL):
3394            this = self.expression(exp.Is, this=this, expression=exp.Null())
3395
3396        # Postgres supports ISNULL and NOTNULL for conditions.
3397        # https://blog.andreiavram.ro/postgresql-null-composite-type/
3398        if self._match(TokenType.NOTNULL):
3399            this = self.expression(exp.Is, this=this, expression=exp.Null())
3400            this = self.expression(exp.Not, this=this)
3401
3402        if negate:
3403            this = self.expression(exp.Not, this=this)
3404
3405        if self._match(TokenType.IS):
3406            this = self._parse_is(this)
3407
3408        return this
3409
3410    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3411        index = self._index - 1
3412        negate = self._match(TokenType.NOT)
3413
3414        if self._match_text_seq("DISTINCT", "FROM"):
3415            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
3416            return self.expression(klass, this=this, expression=self._parse_conjunction())
3417
3418        expression = self._parse_null() or self._parse_boolean()
3419        if not expression:
3420            self._retreat(index)
3421            return None
3422
3423        this = self.expression(exp.Is, this=this, expression=expression)
3424        return self.expression(exp.Not, this=this) if negate else this
3425
3426    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
3427        unnest = self._parse_unnest(with_alias=False)
3428        if unnest:
3429            this = self.expression(exp.In, this=this, unnest=unnest)
3430        elif self._match_set((TokenType.L_PAREN, TokenType.L_BRACKET)):
3431            matched_l_paren = self._prev.token_type == TokenType.L_PAREN
3432            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
3433
3434            if len(expressions) == 1 and isinstance(expressions[0], exp.Subqueryable):
3435                this = self.expression(exp.In, this=this, query=expressions[0])
3436            else:
3437                this = self.expression(exp.In, this=this, expressions=expressions)
3438
3439            if matched_l_paren:
3440                self._match_r_paren(this)
3441            elif not self._match(TokenType.R_BRACKET, expression=this):
3442                self.raise_error("Expecting ]")
3443        else:
3444            this = self.expression(exp.In, this=this, field=self._parse_field())
3445
3446        return this
3447
3448    def _parse_between(self, this: t.Optional[exp.Expression]) -> exp.Between:
3449        low = self._parse_bitwise()
3450        self._match(TokenType.AND)
3451        high = self._parse_bitwise()
3452        return self.expression(exp.Between, this=this, low=low, high=high)
3453
3454    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3455        if not self._match(TokenType.ESCAPE):
3456            return this
3457        return self.expression(exp.Escape, this=this, expression=self._parse_string())
3458
3459    def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Interval]:
3460        index = self._index
3461
3462        if not self._match(TokenType.INTERVAL) and match_interval:
3463            return None
3464
3465        if self._match(TokenType.STRING, advance=False):
3466            this = self._parse_primary()
3467        else:
3468            this = self._parse_term()
3469
3470        if not this or (
3471            isinstance(this, exp.Column)
3472            and not this.table
3473            and not this.this.quoted
3474            and this.name.upper() == "IS"
3475        ):
3476            self._retreat(index)
3477            return None
3478
3479        unit = self._parse_function() or (
3480            not self._match(TokenType.ALIAS, advance=False)
3481            and self._parse_var(any_token=True, upper=True)
3482        )
3483
3484        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
3485        # each INTERVAL expression into this canonical form so it's easy to transpile
3486        if this and this.is_number:
3487            this = exp.Literal.string(this.name)
3488        elif this and this.is_string:
3489            parts = this.name.split()
3490
3491            if len(parts) == 2:
3492                if unit:
3493                    # This is not actually a unit, it's something else (e.g. a "window side")
3494                    unit = None
3495                    self._retreat(self._index - 1)
3496
3497                this = exp.Literal.string(parts[0])
3498                unit = self.expression(exp.Var, this=parts[1].upper())
3499
3500        return self.expression(exp.Interval, this=this, unit=unit)
3501
3502    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
3503        this = self._parse_term()
3504
3505        while True:
3506            if self._match_set(self.BITWISE):
3507                this = self.expression(
3508                    self.BITWISE[self._prev.token_type],
3509                    this=this,
3510                    expression=self._parse_term(),
3511                )
3512            elif self.dialect.DPIPE_IS_STRING_CONCAT and self._match(TokenType.DPIPE):
3513                this = self.expression(
3514                    exp.DPipe,
3515                    this=this,
3516                    expression=self._parse_term(),
3517                    safe=not self.dialect.STRICT_STRING_CONCAT,
3518                )
3519            elif self._match(TokenType.DQMARK):
3520                this = self.expression(exp.Coalesce, this=this, expressions=self._parse_term())
3521            elif self._match_pair(TokenType.LT, TokenType.LT):
3522                this = self.expression(
3523                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
3524                )
3525            elif self._match_pair(TokenType.GT, TokenType.GT):
3526                this = self.expression(
3527                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
3528                )
3529            else:
3530                break
3531
3532        return this
3533
3534    def _parse_term(self) -> t.Optional[exp.Expression]:
3535        return self._parse_tokens(self._parse_factor, self.TERM)
3536
3537    def _parse_factor(self) -> t.Optional[exp.Expression]:
3538        if self.EXPONENT:
3539            factor = self._parse_tokens(self._parse_exponent, self.FACTOR)
3540        else:
3541            factor = self._parse_tokens(self._parse_unary, self.FACTOR)
3542        if isinstance(factor, exp.Div):
3543            factor.args["typed"] = self.dialect.TYPED_DIVISION
3544            factor.args["safe"] = self.dialect.SAFE_DIVISION
3545        return factor
3546
3547    def _parse_exponent(self) -> t.Optional[exp.Expression]:
3548        return self._parse_tokens(self._parse_unary, self.EXPONENT)
3549
3550    def _parse_unary(self) -> t.Optional[exp.Expression]:
3551        if self._match_set(self.UNARY_PARSERS):
3552            return self.UNARY_PARSERS[self._prev.token_type](self)
3553        return self._parse_at_time_zone(self._parse_type())
3554
3555    def _parse_type(self, parse_interval: bool = True) -> t.Optional[exp.Expression]:
3556        interval = parse_interval and self._parse_interval()
3557        if interval:
3558            # Convert INTERVAL 'val_1' unit_1 ... 'val_n' unit_n into a sum of intervals
3559            while self._match_set((TokenType.STRING, TokenType.NUMBER), advance=False):
3560                interval = self.expression(  # type: ignore
3561                    exp.Add, this=interval, expression=self._parse_interval(match_interval=False)
3562                )
3563
3564            return interval
3565
3566        index = self._index
3567        data_type = self._parse_types(check_func=True, allow_identifiers=False)
3568        this = self._parse_column()
3569
3570        if data_type:
3571            if isinstance(this, exp.Literal):
3572                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
3573                if parser:
3574                    return parser(self, this, data_type)
3575                return self.expression(exp.Cast, this=this, to=data_type)
3576            if not data_type.expressions:
3577                self._retreat(index)
3578                return self._parse_column()
3579            return self._parse_column_ops(data_type)
3580
3581        return this and self._parse_column_ops(this)
3582
3583    def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
3584        this = self._parse_type()
3585        if not this:
3586            return None
3587
3588        return self.expression(
3589            exp.DataTypeParam, this=this, expression=self._parse_var(any_token=True)
3590        )
3591
3592    def _parse_types(
3593        self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
3594    ) -> t.Optional[exp.Expression]:
3595        index = self._index
3596
3597        prefix = self._match_text_seq("SYSUDTLIB", ".")
3598
3599        if not self._match_set(self.TYPE_TOKENS):
3600            identifier = allow_identifiers and self._parse_id_var(
3601                any_token=False, tokens=(TokenType.VAR,)
3602            )
3603
3604            if identifier:
3605                tokens = self.dialect.tokenize(identifier.name)
3606
3607                if len(tokens) != 1:
3608                    self.raise_error("Unexpected identifier", self._prev)
3609
3610                if tokens[0].token_type in self.TYPE_TOKENS:
3611                    self._prev = tokens[0]
3612                elif self.dialect.SUPPORTS_USER_DEFINED_TYPES:
3613                    type_name = identifier.name
3614
3615                    while self._match(TokenType.DOT):
3616                        type_name = f"{type_name}.{self._advance_any() and self._prev.text}"
3617
3618                    return exp.DataType.build(type_name, udt=True)
3619                else:
3620                    return None
3621            else:
3622                return None
3623
3624        type_token = self._prev.token_type
3625
3626        if type_token == TokenType.PSEUDO_TYPE:
3627            return self.expression(exp.PseudoType, this=self._prev.text.upper())
3628
3629        if type_token == TokenType.OBJECT_IDENTIFIER:
3630            return self.expression(exp.ObjectIdentifier, this=self._prev.text.upper())
3631
3632        nested = type_token in self.NESTED_TYPE_TOKENS
3633        is_struct = type_token in self.STRUCT_TYPE_TOKENS
3634        expressions = None
3635        maybe_func = False
3636
3637        if self._match(TokenType.L_PAREN):
3638            if is_struct:
3639                expressions = self._parse_csv(self._parse_struct_types)
3640            elif nested:
3641                expressions = self._parse_csv(
3642                    lambda: self._parse_types(
3643                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
3644                    )
3645                )
3646            elif type_token in self.ENUM_TYPE_TOKENS:
3647                expressions = self._parse_csv(self._parse_equality)
3648            else:
3649                expressions = self._parse_csv(self._parse_type_size)
3650
3651            if not expressions or not self._match(TokenType.R_PAREN):
3652                self._retreat(index)
3653                return None
3654
3655            maybe_func = True
3656
3657        this: t.Optional[exp.Expression] = None
3658        values: t.Optional[t.List[exp.Expression]] = None
3659
3660        if nested and self._match(TokenType.LT):
3661            if is_struct:
3662                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
3663            else:
3664                expressions = self._parse_csv(
3665                    lambda: self._parse_types(
3666                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
3667                    )
3668                )
3669
3670            if not self._match(TokenType.GT):
3671                self.raise_error("Expecting >")
3672
3673            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
3674                values = self._parse_csv(self._parse_conjunction)
3675                self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
3676
3677        if type_token in self.TIMESTAMPS:
3678            if self._match_text_seq("WITH", "TIME", "ZONE"):
3679                maybe_func = False
3680                tz_type = (
3681                    exp.DataType.Type.TIMETZ
3682                    if type_token in self.TIMES
3683                    else exp.DataType.Type.TIMESTAMPTZ
3684                )
3685                this = exp.DataType(this=tz_type, expressions=expressions)
3686            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
3687                maybe_func = False
3688                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
3689            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
3690                maybe_func = False
3691        elif type_token == TokenType.INTERVAL:
3692            unit = self._parse_var()
3693
3694            if self._match_text_seq("TO"):
3695                span = [exp.IntervalSpan(this=unit, expression=self._parse_var())]
3696            else:
3697                span = None
3698
3699            if span or not unit:
3700                this = self.expression(
3701                    exp.DataType, this=exp.DataType.Type.INTERVAL, expressions=span
3702                )
3703            else:
3704                this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
3705
3706        if maybe_func and check_func:
3707            index2 = self._index
3708            peek = self._parse_string()
3709
3710            if not peek:
3711                self._retreat(index)
3712                return None
3713
3714            self._retreat(index2)
3715
3716        if not this:
3717            if self._match_text_seq("UNSIGNED"):
3718                unsigned_type_token = self.SIGNED_TO_UNSIGNED_TYPE_TOKEN.get(type_token)
3719                if not unsigned_type_token:
3720                    self.raise_error(f"Cannot convert {type_token.value} to unsigned.")
3721
3722                type_token = unsigned_type_token or type_token
3723
3724            this = exp.DataType(
3725                this=exp.DataType.Type[type_token.value],
3726                expressions=expressions,
3727                nested=nested,
3728                values=values,
3729                prefix=prefix,
3730            )
3731
3732        while self._match_pair(TokenType.L_BRACKET, TokenType.R_BRACKET):
3733            this = exp.DataType(this=exp.DataType.Type.ARRAY, expressions=[this], nested=True)
3734
3735        return this
3736
3737    def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
3738        index = self._index
3739        this = self._parse_type(parse_interval=False) or self._parse_id_var()
3740        self._match(TokenType.COLON)
3741        column_def = self._parse_column_def(this)
3742
3743        if type_required and (
3744            (isinstance(this, exp.Column) and this.this is column_def) or this is column_def
3745        ):
3746            self._retreat(index)
3747            return self._parse_types()
3748
3749        return column_def
3750
3751    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3752        if not self._match_text_seq("AT", "TIME", "ZONE"):
3753            return this
3754        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
3755
3756    def _parse_column(self) -> t.Optional[exp.Expression]:
3757        this = self._parse_field()
3758        if isinstance(this, exp.Identifier):
3759            this = self.expression(exp.Column, this=this)
3760        elif not this:
3761            return self._parse_bracket(this)
3762        return self._parse_column_ops(this)
3763
3764    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3765        this = self._parse_bracket(this)
3766
3767        while self._match_set(self.COLUMN_OPERATORS):
3768            op_token = self._prev.token_type
3769            op = self.COLUMN_OPERATORS.get(op_token)
3770
3771            if op_token == TokenType.DCOLON:
3772                field = self._parse_types()
3773                if not field:
3774                    self.raise_error("Expected type")
3775            elif op and self._curr:
3776                self._advance()
3777                value = self._prev.text
3778                field = (
3779                    exp.Literal.number(value)
3780                    if self._prev.token_type == TokenType.NUMBER
3781                    else exp.Literal.string(value)
3782                )
3783            else:
3784                field = self._parse_field(anonymous_func=True, any_token=True)
3785
3786            if isinstance(field, exp.Func):
3787                # bigquery allows function calls like x.y.count(...)
3788                # SAFE.SUBSTR(...)
3789                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
3790                this = self._replace_columns_with_dots(this)
3791
3792            if op:
3793                this = op(self, this, field)
3794            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
3795                this = self.expression(
3796                    exp.Column,
3797                    this=field,
3798                    table=this.this,
3799                    db=this.args.get("table"),
3800                    catalog=this.args.get("db"),
3801                )
3802            else:
3803                this = self.expression(exp.Dot, this=this, expression=field)
3804            this = self._parse_bracket(this)
3805        return this
3806
3807    def _parse_primary(self) -> t.Optional[exp.Expression]:
3808        if self._match_set(self.PRIMARY_PARSERS):
3809            token_type = self._prev.token_type
3810            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
3811
3812            if token_type == TokenType.STRING:
3813                expressions = [primary]
3814                while self._match(TokenType.STRING):
3815                    expressions.append(exp.Literal.string(self._prev.text))
3816
3817                if len(expressions) > 1:
3818                    return self.expression(exp.Concat, expressions=expressions)
3819
3820            return primary
3821
3822        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
3823            return exp.Literal.number(f"0.{self._prev.text}")
3824
3825        if self._match(TokenType.L_PAREN):
3826            comments = self._prev_comments
3827            query = self._parse_select()
3828
3829            if query:
3830                expressions = [query]
3831            else:
3832                expressions = self._parse_expressions()
3833
3834            this = self._parse_query_modifiers(seq_get(expressions, 0))
3835
3836            if isinstance(this, exp.Subqueryable):
3837                this = self._parse_set_operations(
3838                    self._parse_subquery(this=this, parse_alias=False)
3839                )
3840            elif len(expressions) > 1:
3841                this = self.expression(exp.Tuple, expressions=expressions)
3842            else:
3843                this = self.expression(exp.Paren, this=self._parse_set_operations(this))
3844
3845            if this:
3846                this.add_comments(comments)
3847
3848            self._match_r_paren(expression=this)
3849            return this
3850
3851        return None
3852
3853    def _parse_field(
3854        self,
3855        any_token: bool = False,
3856        tokens: t.Optional[t.Collection[TokenType]] = None,
3857        anonymous_func: bool = False,
3858    ) -> t.Optional[exp.Expression]:
3859        return (
3860            self._parse_primary()
3861            or self._parse_function(anonymous=anonymous_func)
3862            or self._parse_id_var(any_token=any_token, tokens=tokens)
3863        )
3864
3865    def _parse_function(
3866        self,
3867        functions: t.Optional[t.Dict[str, t.Callable]] = None,
3868        anonymous: bool = False,
3869        optional_parens: bool = True,
3870    ) -> t.Optional[exp.Expression]:
3871        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
3872        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
3873        fn_syntax = False
3874        if (
3875            self._match(TokenType.L_BRACE, advance=False)
3876            and self._next
3877            and self._next.text.upper() == "FN"
3878        ):
3879            self._advance(2)
3880            fn_syntax = True
3881
3882        func = self._parse_function_call(
3883            functions=functions, anonymous=anonymous, optional_parens=optional_parens
3884        )
3885
3886        if fn_syntax:
3887            self._match(TokenType.R_BRACE)
3888
3889        return func
3890
3891    def _parse_function_call(
3892        self,
3893        functions: t.Optional[t.Dict[str, t.Callable]] = None,
3894        anonymous: bool = False,
3895        optional_parens: bool = True,
3896    ) -> t.Optional[exp.Expression]:
3897        if not self._curr:
3898            return None
3899
3900        comments = self._curr.comments
3901        token_type = self._curr.token_type
3902        this = self._curr.text
3903        upper = this.upper()
3904
3905        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
3906        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
3907            self._advance()
3908            return parser(self)
3909
3910        if not self._next or self._next.token_type != TokenType.L_PAREN:
3911            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
3912                self._advance()
3913                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
3914
3915            return None
3916
3917        if token_type not in self.FUNC_TOKENS:
3918            return None
3919
3920        self._advance(2)
3921
3922        parser = self.FUNCTION_PARSERS.get(upper)
3923        if parser and not anonymous:
3924            this = parser(self)
3925        else:
3926            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
3927
3928            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
3929                this = self.expression(subquery_predicate, this=self._parse_select())
3930                self._match_r_paren()
3931                return this
3932
3933            if functions is None:
3934                functions = self.FUNCTIONS
3935
3936            function = functions.get(upper)
3937
3938            alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS
3939            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
3940
3941            if function and not anonymous:
3942                if "dialect" in function.__code__.co_varnames:
3943                    func = function(args, dialect=self.dialect)
3944                else:
3945                    func = function(args)
3946
3947                func = self.validate_expression(func, args)
3948                if not self.dialect.NORMALIZE_FUNCTIONS:
3949                    func.meta["name"] = this
3950
3951                this = func
3952            else:
3953                this = self.expression(exp.Anonymous, this=this, expressions=args)
3954
3955        if isinstance(this, exp.Expression):
3956            this.add_comments(comments)
3957
3958        self._match_r_paren(this)
3959        return self._parse_window(this)
3960
3961    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
3962        return self._parse_column_def(self._parse_id_var())
3963
3964    def _parse_user_defined_function(
3965        self, kind: t.Optional[TokenType] = None
3966    ) -> t.Optional[exp.Expression]:
3967        this = self._parse_id_var()
3968
3969        while self._match(TokenType.DOT):
3970            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
3971
3972        if not self._match(TokenType.L_PAREN):
3973            return this
3974
3975        expressions = self._parse_csv(self._parse_function_parameter)
3976        self._match_r_paren()
3977        return self.expression(
3978            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
3979        )
3980
3981    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
3982        literal = self._parse_primary()
3983        if literal:
3984            return self.expression(exp.Introducer, this=token.text, expression=literal)
3985
3986        return self.expression(exp.Identifier, this=token.text)
3987
3988    def _parse_session_parameter(self) -> exp.SessionParameter:
3989        kind = None
3990        this = self._parse_id_var() or self._parse_primary()
3991
3992        if this and self._match(TokenType.DOT):
3993            kind = this.name
3994            this = self._parse_var() or self._parse_primary()
3995
3996        return self.expression(exp.SessionParameter, this=this, kind=kind)
3997
3998    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
3999        index = self._index
4000
4001        if self._match(TokenType.L_PAREN):
4002            expressions = t.cast(
4003                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_id_var)
4004            )
4005
4006            if not self._match(TokenType.R_PAREN):
4007                self._retreat(index)
4008        else:
4009            expressions = [self._parse_id_var()]
4010
4011        if self._match_set(self.LAMBDAS):
4012            return self.LAMBDAS[self._prev.token_type](self, expressions)
4013
4014        self._retreat(index)
4015
4016        this: t.Optional[exp.Expression]
4017
4018        if self._match(TokenType.DISTINCT):
4019            this = self.expression(
4020                exp.Distinct, expressions=self._parse_csv(self._parse_conjunction)
4021            )
4022        else:
4023            this = self._parse_select_or_expression(alias=alias)
4024
4025        return self._parse_limit(self._parse_order(self._parse_respect_or_ignore_nulls(this)))
4026
4027    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4028        index = self._index
4029
4030        if not self.errors:
4031            try:
4032                if self._parse_select(nested=True):
4033                    return this
4034            except ParseError:
4035                pass
4036            finally:
4037                self.errors.clear()
4038                self._retreat(index)
4039
4040        if not self._match(TokenType.L_PAREN):
4041            return this
4042
4043        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
4044
4045        self._match_r_paren()
4046        return self.expression(exp.Schema, this=this, expressions=args)
4047
4048    def _parse_field_def(self) -> t.Optional[exp.Expression]:
4049        return self._parse_column_def(self._parse_field(any_token=True))
4050
4051    def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4052        # column defs are not really columns, they're identifiers
4053        if isinstance(this, exp.Column):
4054            this = this.this
4055
4056        kind = self._parse_types(schema=True)
4057
4058        if self._match_text_seq("FOR", "ORDINALITY"):
4059            return self.expression(exp.ColumnDef, this=this, ordinality=True)
4060
4061        constraints: t.List[exp.Expression] = []
4062
4063        if not kind and self._match(TokenType.ALIAS):
4064            constraints.append(
4065                self.expression(
4066                    exp.ComputedColumnConstraint,
4067                    this=self._parse_conjunction(),
4068                    persisted=self._match_text_seq("PERSISTED"),
4069                    not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
4070                )
4071            )
4072        elif kind and self._match_pair(TokenType.ALIAS, TokenType.L_PAREN, advance=False):
4073            self._match(TokenType.ALIAS)
4074            constraints.append(
4075                self.expression(exp.TransformColumnConstraint, this=self._parse_field())
4076            )
4077
4078        while True:
4079            constraint = self._parse_column_constraint()
4080            if not constraint:
4081                break
4082            constraints.append(constraint)
4083
4084        if not kind and not constraints:
4085            return this
4086
4087        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
4088
4089    def _parse_auto_increment(
4090        self,
4091    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
4092        start = None
4093        increment = None
4094
4095        if self._match(TokenType.L_PAREN, advance=False):
4096            args = self._parse_wrapped_csv(self._parse_bitwise)
4097            start = seq_get(args, 0)
4098            increment = seq_get(args, 1)
4099        elif self._match_text_seq("START"):
4100            start = self._parse_bitwise()
4101            self._match_text_seq("INCREMENT")
4102            increment = self._parse_bitwise()
4103
4104        if start and increment:
4105            return exp.GeneratedAsIdentityColumnConstraint(start=start, increment=increment)
4106
4107        return exp.AutoIncrementColumnConstraint()
4108
4109    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
4110        if not self._match_text_seq("REFRESH"):
4111            self._retreat(self._index - 1)
4112            return None
4113        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
4114
4115    def _parse_compress(self) -> exp.CompressColumnConstraint:
4116        if self._match(TokenType.L_PAREN, advance=False):
4117            return self.expression(
4118                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
4119            )
4120
4121        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
4122
4123    def _parse_generated_as_identity(
4124        self,
4125    ) -> (
4126        exp.GeneratedAsIdentityColumnConstraint
4127        | exp.ComputedColumnConstraint
4128        | exp.GeneratedAsRowColumnConstraint
4129    ):
4130        if self._match_text_seq("BY", "DEFAULT"):
4131            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
4132            this = self.expression(
4133                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
4134            )
4135        else:
4136            self._match_text_seq("ALWAYS")
4137            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
4138
4139        self._match(TokenType.ALIAS)
4140
4141        if self._match_text_seq("ROW"):
4142            start = self._match_text_seq("START")
4143            if not start:
4144                self._match(TokenType.END)
4145            hidden = self._match_text_seq("HIDDEN")
4146            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
4147
4148        identity = self._match_text_seq("IDENTITY")
4149
4150        if self._match(TokenType.L_PAREN):
4151            if self._match(TokenType.START_WITH):
4152                this.set("start", self._parse_bitwise())
4153            if self._match_text_seq("INCREMENT", "BY"):
4154                this.set("increment", self._parse_bitwise())
4155            if self._match_text_seq("MINVALUE"):
4156                this.set("minvalue", self._parse_bitwise())
4157            if self._match_text_seq("MAXVALUE"):
4158                this.set("maxvalue", self._parse_bitwise())
4159
4160            if self._match_text_seq("CYCLE"):
4161                this.set("cycle", True)
4162            elif self._match_text_seq("NO", "CYCLE"):
4163                this.set("cycle", False)
4164
4165            if not identity:
4166                this.set("expression", self._parse_bitwise())
4167            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
4168                args = self._parse_csv(self._parse_bitwise)
4169                this.set("start", seq_get(args, 0))
4170                this.set("increment", seq_get(args, 1))
4171
4172            self._match_r_paren()
4173
4174        return this
4175
4176    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
4177        self._match_text_seq("LENGTH")
4178        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
4179
4180    def _parse_not_constraint(
4181        self,
4182    ) -> t.Optional[exp.Expression]:
4183        if self._match_text_seq("NULL"):
4184            return self.expression(exp.NotNullColumnConstraint)
4185        if self._match_text_seq("CASESPECIFIC"):
4186            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
4187        if self._match_text_seq("FOR", "REPLICATION"):
4188            return self.expression(exp.NotForReplicationColumnConstraint)
4189        return None
4190
4191    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
4192        if self._match(TokenType.CONSTRAINT):
4193            this = self._parse_id_var()
4194        else:
4195            this = None
4196
4197        if self._match_texts(self.CONSTRAINT_PARSERS):
4198            return self.expression(
4199                exp.ColumnConstraint,
4200                this=this,
4201                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
4202            )
4203
4204        return this
4205
4206    def _parse_constraint(self) -> t.Optional[exp.Expression]:
4207        if not self._match(TokenType.CONSTRAINT):
4208            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
4209
4210        this = self._parse_id_var()
4211        expressions = []
4212
4213        while True:
4214            constraint = self._parse_unnamed_constraint() or self._parse_function()
4215            if not constraint:
4216                break
4217            expressions.append(constraint)
4218
4219        return self.expression(exp.Constraint, this=this, expressions=expressions)
4220
4221    def _parse_unnamed_constraint(
4222        self, constraints: t.Optional[t.Collection[str]] = None
4223    ) -> t.Optional[exp.Expression]:
4224        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
4225            constraints or self.CONSTRAINT_PARSERS
4226        ):
4227            return None
4228
4229        constraint = self._prev.text.upper()
4230        if constraint not in self.CONSTRAINT_PARSERS:
4231            self.raise_error(f"No parser found for schema constraint {constraint}.")
4232
4233        return self.CONSTRAINT_PARSERS[constraint](self)
4234
4235    def _parse_unique(self) -> exp.UniqueColumnConstraint:
4236        self._match_text_seq("KEY")
4237        return self.expression(
4238            exp.UniqueColumnConstraint,
4239            this=self._parse_schema(self._parse_id_var(any_token=False)),
4240            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
4241        )
4242
4243    def _parse_key_constraint_options(self) -> t.List[str]:
4244        options = []
4245        while True:
4246            if not self._curr:
4247                break
4248
4249            if self._match(TokenType.ON):
4250                action = None
4251                on = self._advance_any() and self._prev.text
4252
4253                if self._match_text_seq("NO", "ACTION"):
4254                    action = "NO ACTION"
4255                elif self._match_text_seq("CASCADE"):
4256                    action = "CASCADE"
4257                elif self._match_text_seq("RESTRICT"):
4258                    action = "RESTRICT"
4259                elif self._match_pair(TokenType.SET, TokenType.NULL):
4260                    action = "SET NULL"
4261                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
4262                    action = "SET DEFAULT"
4263                else:
4264                    self.raise_error("Invalid key constraint")
4265
4266                options.append(f"ON {on} {action}")
4267            elif self._match_text_seq("NOT", "ENFORCED"):
4268                options.append("NOT ENFORCED")
4269            elif self._match_text_seq("DEFERRABLE"):
4270                options.append("DEFERRABLE")
4271            elif self._match_text_seq("INITIALLY", "DEFERRED"):
4272                options.append("INITIALLY DEFERRED")
4273            elif self._match_text_seq("NORELY"):
4274                options.append("NORELY")
4275            elif self._match_text_seq("MATCH", "FULL"):
4276                options.append("MATCH FULL")
4277            else:
4278                break
4279
4280        return options
4281
4282    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
4283        if match and not self._match(TokenType.REFERENCES):
4284            return None
4285
4286        expressions = None
4287        this = self._parse_table(schema=True)
4288        options = self._parse_key_constraint_options()
4289        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
4290
4291    def _parse_foreign_key(self) -> exp.ForeignKey:
4292        expressions = self._parse_wrapped_id_vars()
4293        reference = self._parse_references()
4294        options = {}
4295
4296        while self._match(TokenType.ON):
4297            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
4298                self.raise_error("Expected DELETE or UPDATE")
4299
4300            kind = self._prev.text.lower()
4301
4302            if self._match_text_seq("NO", "ACTION"):
4303                action = "NO ACTION"
4304            elif self._match(TokenType.SET):
4305                self._match_set((TokenType.NULL, TokenType.DEFAULT))
4306                action = "SET " + self._prev.text.upper()
4307            else:
4308                self._advance()
4309                action = self._prev.text.upper()
4310
4311            options[kind] = action
4312
4313        return self.expression(
4314            exp.ForeignKey, expressions=expressions, reference=reference, **options  # type: ignore
4315        )
4316
4317    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
4318        return self._parse_field()
4319
4320    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
4321        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
4322            self._retreat(self._index - 1)
4323            return None
4324
4325        id_vars = self._parse_wrapped_id_vars()
4326        return self.expression(
4327            exp.PeriodForSystemTimeConstraint,
4328            this=seq_get(id_vars, 0),
4329            expression=seq_get(id_vars, 1),
4330        )
4331
4332    def _parse_primary_key(
4333        self, wrapped_optional: bool = False, in_props: bool = False
4334    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
4335        desc = (
4336            self._match_set((TokenType.ASC, TokenType.DESC))
4337            and self._prev.token_type == TokenType.DESC
4338        )
4339
4340        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
4341            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
4342
4343        expressions = self._parse_wrapped_csv(
4344            self._parse_primary_key_part, optional=wrapped_optional
4345        )
4346        options = self._parse_key_constraint_options()
4347        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
4348
4349    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
4350        return self._parse_slice(self._parse_alias(self._parse_conjunction(), explicit=True))
4351
4352    def _parse_bracket(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4353        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
4354            return this
4355
4356        bracket_kind = self._prev.token_type
4357        expressions = self._parse_csv(
4358            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
4359        )
4360
4361        if not self._match(TokenType.R_BRACKET) and bracket_kind == TokenType.L_BRACKET:
4362            self.raise_error("Expected ]")
4363        elif not self._match(TokenType.R_BRACE) and bracket_kind == TokenType.L_BRACE:
4364            self.raise_error("Expected }")
4365
4366        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
4367        if bracket_kind == TokenType.L_BRACE:
4368            this = self.expression(exp.Struct, expressions=expressions)
4369        elif not this or this.name.upper() == "ARRAY":
4370            this = self.expression(exp.Array, expressions=expressions)
4371        else:
4372            expressions = apply_index_offset(this, expressions, -self.dialect.INDEX_OFFSET)
4373            this = self.expression(exp.Bracket, this=this, expressions=expressions)
4374
4375        self._add_comments(this)
4376        return self._parse_bracket(this)
4377
4378    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4379        if self._match(TokenType.COLON):
4380            return self.expression(exp.Slice, this=this, expression=self._parse_conjunction())
4381        return this
4382
4383    def _parse_case(self) -> t.Optional[exp.Expression]:
4384        ifs = []
4385        default = None
4386
4387        comments = self._prev_comments
4388        expression = self._parse_conjunction()
4389
4390        while self._match(TokenType.WHEN):
4391            this = self._parse_conjunction()
4392            self._match(TokenType.THEN)
4393            then = self._parse_conjunction()
4394            ifs.append(self.expression(exp.If, this=this, true=then))
4395
4396        if self._match(TokenType.ELSE):
4397            default = self._parse_conjunction()
4398
4399        if not self._match(TokenType.END):
4400            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
4401                default = exp.column("interval")
4402            else:
4403                self.raise_error("Expected END after CASE", self._prev)
4404
4405        return self._parse_window(
4406            self.expression(exp.Case, comments=comments, this=expression, ifs=ifs, default=default)
4407        )
4408
4409    def _parse_if(self) -> t.Optional[exp.Expression]:
4410        if self._match(TokenType.L_PAREN):
4411            args = self._parse_csv(self._parse_conjunction)
4412            this = self.validate_expression(exp.If.from_arg_list(args), args)
4413            self._match_r_paren()
4414        else:
4415            index = self._index - 1
4416            condition = self._parse_conjunction()
4417
4418            if not condition:
4419                self._retreat(index)
4420                return None
4421
4422            self._match(TokenType.THEN)
4423            true = self._parse_conjunction()
4424            false = self._parse_conjunction() if self._match(TokenType.ELSE) else None
4425            self._match(TokenType.END)
4426            this = self.expression(exp.If, this=condition, true=true, false=false)
4427
4428        return self._parse_window(this)
4429
4430    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
4431        if not self._match_text_seq("VALUE", "FOR"):
4432            self._retreat(self._index - 1)
4433            return None
4434
4435        return self.expression(
4436            exp.NextValueFor,
4437            this=self._parse_column(),
4438            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
4439        )
4440
4441    def _parse_extract(self) -> exp.Extract:
4442        this = self._parse_function() or self._parse_var() or self._parse_type()
4443
4444        if self._match(TokenType.FROM):
4445            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
4446
4447        if not self._match(TokenType.COMMA):
4448            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
4449
4450        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
4451
4452    def _parse_any_value(self) -> exp.AnyValue:
4453        this = self._parse_lambda()
4454        is_max = None
4455        having = None
4456
4457        if self._match(TokenType.HAVING):
4458            self._match_texts(("MAX", "MIN"))
4459            is_max = self._prev.text == "MAX"
4460            having = self._parse_column()
4461
4462        return self.expression(exp.AnyValue, this=this, having=having, max=is_max)
4463
4464    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
4465        this = self._parse_conjunction()
4466
4467        if not self._match(TokenType.ALIAS):
4468            if self._match(TokenType.COMMA):
4469                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
4470
4471            self.raise_error("Expected AS after CAST")
4472
4473        fmt = None
4474        to = self._parse_types()
4475
4476        if self._match(TokenType.FORMAT):
4477            fmt_string = self._parse_string()
4478            fmt = self._parse_at_time_zone(fmt_string)
4479
4480            if not to:
4481                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
4482            if to.this in exp.DataType.TEMPORAL_TYPES:
4483                this = self.expression(
4484                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
4485                    this=this,
4486                    format=exp.Literal.string(
4487                        format_time(
4488                            fmt_string.this if fmt_string else "",
4489                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
4490                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
4491                        )
4492                    ),
4493                )
4494
4495                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
4496                    this.set("zone", fmt.args["zone"])
4497                return this
4498        elif not to:
4499            self.raise_error("Expected TYPE after CAST")
4500        elif isinstance(to, exp.Identifier):
4501            to = exp.DataType.build(to.name, udt=True)
4502        elif to.this == exp.DataType.Type.CHAR:
4503            if self._match(TokenType.CHARACTER_SET):
4504                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
4505
4506        return self.expression(
4507            exp.Cast if strict else exp.TryCast, this=this, to=to, format=fmt, safe=safe
4508        )
4509
4510    def _parse_string_agg(self) -> exp.Expression:
4511        if self._match(TokenType.DISTINCT):
4512            args: t.List[t.Optional[exp.Expression]] = [
4513                self.expression(exp.Distinct, expressions=[self._parse_conjunction()])
4514            ]
4515            if self._match(TokenType.COMMA):
4516                args.extend(self._parse_csv(self._parse_conjunction))
4517        else:
4518            args = self._parse_csv(self._parse_conjunction)  # type: ignore
4519
4520        index = self._index
4521        if not self._match(TokenType.R_PAREN) and args:
4522            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
4523            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
4524            args[-1] = self._parse_limit(this=self._parse_order(this=args[-1]))
4525            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
4526
4527        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
4528        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
4529        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
4530        if not self._match_text_seq("WITHIN", "GROUP"):
4531            self._retreat(index)
4532            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
4533
4534        self._match_l_paren()  # The corresponding match_r_paren will be called in parse_function (caller)
4535        order = self._parse_order(this=seq_get(args, 0))
4536        return self.expression(exp.GroupConcat, this=order, separator=seq_get(args, 1))
4537
4538    def _parse_convert(
4539        self, strict: bool, safe: t.Optional[bool] = None
4540    ) -> t.Optional[exp.Expression]:
4541        this = self._parse_bitwise()
4542
4543        if self._match(TokenType.USING):
4544            to: t.Optional[exp.Expression] = self.expression(
4545                exp.CharacterSet, this=self._parse_var()
4546            )
4547        elif self._match(TokenType.COMMA):
4548            to = self._parse_types()
4549        else:
4550            to = None
4551
4552        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
4553
4554    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
4555        """
4556        There are generally two variants of the DECODE function:
4557
4558        - DECODE(bin, charset)
4559        - DECODE(expression, search, result [, search, result] ... [, default])
4560
4561        The second variant will always be parsed into a CASE expression. Note that NULL
4562        needs special treatment, since we need to explicitly check for it with `IS NULL`,
4563        instead of relying on pattern matching.
4564        """
4565        args = self._parse_csv(self._parse_conjunction)
4566
4567        if len(args) < 3:
4568            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
4569
4570        expression, *expressions = args
4571        if not expression:
4572            return None
4573
4574        ifs = []
4575        for search, result in zip(expressions[::2], expressions[1::2]):
4576            if not search or not result:
4577                return None
4578
4579            if isinstance(search, exp.Literal):
4580                ifs.append(
4581                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
4582                )
4583            elif isinstance(search, exp.Null):
4584                ifs.append(
4585                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
4586                )
4587            else:
4588                cond = exp.or_(
4589                    exp.EQ(this=expression.copy(), expression=search),
4590                    exp.and_(
4591                        exp.Is(this=expression.copy(), expression=exp.Null()),
4592                        exp.Is(this=search.copy(), expression=exp.Null()),
4593                        copy=False,
4594                    ),
4595                    copy=False,
4596                )
4597                ifs.append(exp.If(this=cond, true=result))
4598
4599        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
4600
4601    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
4602        self._match_text_seq("KEY")
4603        key = self._parse_column()
4604        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
4605        self._match_text_seq("VALUE")
4606        value = self._parse_bitwise()
4607
4608        if not key and not value:
4609            return None
4610        return self.expression(exp.JSONKeyValue, this=key, expression=value)
4611
4612    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4613        if not this or not self._match_text_seq("FORMAT", "JSON"):
4614            return this
4615
4616        return self.expression(exp.FormatJson, this=this)
4617
4618    def _parse_on_handling(self, on: str, *values: str) -> t.Optional[str]:
4619        # Parses the "X ON Y" syntax, i.e. NULL ON NULL (Oracle, T-SQL)
4620        for value in values:
4621            if self._match_text_seq(value, "ON", on):
4622                return f"{value} ON {on}"
4623
4624        return None
4625
4626    @t.overload
4627    def _parse_json_object(self, agg: Literal[False]) -> exp.JSONObject:
4628        ...
4629
4630    @t.overload
4631    def _parse_json_object(self, agg: Literal[True]) -> exp.JSONObjectAgg:
4632        ...
4633
4634    def _parse_json_object(self, agg=False):
4635        star = self._parse_star()
4636        expressions = (
4637            [star]
4638            if star
4639            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
4640        )
4641        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
4642
4643        unique_keys = None
4644        if self._match_text_seq("WITH", "UNIQUE"):
4645            unique_keys = True
4646        elif self._match_text_seq("WITHOUT", "UNIQUE"):
4647            unique_keys = False
4648
4649        self._match_text_seq("KEYS")
4650
4651        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
4652            self._parse_type()
4653        )
4654        encoding = self._match_text_seq("ENCODING") and self._parse_var()
4655
4656        return self.expression(
4657            exp.JSONObjectAgg if agg else exp.JSONObject,
4658            expressions=expressions,
4659            null_handling=null_handling,
4660            unique_keys=unique_keys,
4661            return_type=return_type,
4662            encoding=encoding,
4663        )
4664
4665    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
4666    def _parse_json_column_def(self) -> exp.JSONColumnDef:
4667        if not self._match_text_seq("NESTED"):
4668            this = self._parse_id_var()
4669            kind = self._parse_types(allow_identifiers=False)
4670            nested = None
4671        else:
4672            this = None
4673            kind = None
4674            nested = True
4675
4676        path = self._match_text_seq("PATH") and self._parse_string()
4677        nested_schema = nested and self._parse_json_schema()
4678
4679        return self.expression(
4680            exp.JSONColumnDef,
4681            this=this,
4682            kind=kind,
4683            path=path,
4684            nested_schema=nested_schema,
4685        )
4686
4687    def _parse_json_schema(self) -> exp.JSONSchema:
4688        self._match_text_seq("COLUMNS")
4689        return self.expression(
4690            exp.JSONSchema,
4691            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
4692        )
4693
4694    def _parse_json_table(self) -> exp.JSONTable:
4695        this = self._parse_format_json(self._parse_bitwise())
4696        path = self._match(TokenType.COMMA) and self._parse_string()
4697        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
4698        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
4699        schema = self._parse_json_schema()
4700
4701        return exp.JSONTable(
4702            this=this,
4703            schema=schema,
4704            path=path,
4705            error_handling=error_handling,
4706            empty_handling=empty_handling,
4707        )
4708
4709    def _parse_match_against(self) -> exp.MatchAgainst:
4710        expressions = self._parse_csv(self._parse_column)
4711
4712        self._match_text_seq(")", "AGAINST", "(")
4713
4714        this = self._parse_string()
4715
4716        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
4717            modifier = "IN NATURAL LANGUAGE MODE"
4718            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
4719                modifier = f"{modifier} WITH QUERY EXPANSION"
4720        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
4721            modifier = "IN BOOLEAN MODE"
4722        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
4723            modifier = "WITH QUERY EXPANSION"
4724        else:
4725            modifier = None
4726
4727        return self.expression(
4728            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
4729        )
4730
4731    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
4732    def _parse_open_json(self) -> exp.OpenJSON:
4733        this = self._parse_bitwise()
4734        path = self._match(TokenType.COMMA) and self._parse_string()
4735
4736        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
4737            this = self._parse_field(any_token=True)
4738            kind = self._parse_types()
4739            path = self._parse_string()
4740            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
4741
4742            return self.expression(
4743                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
4744            )
4745
4746        expressions = None
4747        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
4748            self._match_l_paren()
4749            expressions = self._parse_csv(_parse_open_json_column_def)
4750
4751        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
4752
4753    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
4754        args = self._parse_csv(self._parse_bitwise)
4755
4756        if self._match(TokenType.IN):
4757            return self.expression(
4758                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
4759            )
4760
4761        if haystack_first:
4762            haystack = seq_get(args, 0)
4763            needle = seq_get(args, 1)
4764        else:
4765            needle = seq_get(args, 0)
4766            haystack = seq_get(args, 1)
4767
4768        return self.expression(
4769            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
4770        )
4771
4772    def _parse_predict(self) -> exp.Predict:
4773        self._match_text_seq("MODEL")
4774        this = self._parse_table()
4775
4776        self._match(TokenType.COMMA)
4777        self._match_text_seq("TABLE")
4778
4779        return self.expression(
4780            exp.Predict,
4781            this=this,
4782            expression=self._parse_table(),
4783            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
4784        )
4785
4786    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
4787        args = self._parse_csv(self._parse_table)
4788        return exp.JoinHint(this=func_name.upper(), expressions=args)
4789
4790    def _parse_substring(self) -> exp.Substring:
4791        # Postgres supports the form: substring(string [from int] [for int])
4792        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
4793
4794        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
4795
4796        if self._match(TokenType.FROM):
4797            args.append(self._parse_bitwise())
4798            if self._match(TokenType.FOR):
4799                args.append(self._parse_bitwise())
4800
4801        return self.validate_expression(exp.Substring.from_arg_list(args), args)
4802
4803    def _parse_trim(self) -> exp.Trim:
4804        # https://www.w3resource.com/sql/character-functions/trim.php
4805        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
4806
4807        position = None
4808        collation = None
4809        expression = None
4810
4811        if self._match_texts(self.TRIM_TYPES):
4812            position = self._prev.text.upper()
4813
4814        this = self._parse_bitwise()
4815        if self._match_set((TokenType.FROM, TokenType.COMMA)):
4816            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
4817            expression = self._parse_bitwise()
4818
4819            if invert_order:
4820                this, expression = expression, this
4821
4822        if self._match(TokenType.COLLATE):
4823            collation = self._parse_bitwise()
4824
4825        return self.expression(
4826            exp.Trim, this=this, position=position, expression=expression, collation=collation
4827        )
4828
4829    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
4830        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
4831
4832    def _parse_named_window(self) -> t.Optional[exp.Expression]:
4833        return self._parse_window(self._parse_id_var(), alias=True)
4834
4835    def _parse_respect_or_ignore_nulls(
4836        self, this: t.Optional[exp.Expression]
4837    ) -> t.Optional[exp.Expression]:
4838        if self._match_text_seq("IGNORE", "NULLS"):
4839            return self.expression(exp.IgnoreNulls, this=this)
4840        if self._match_text_seq("RESPECT", "NULLS"):
4841            return self.expression(exp.RespectNulls, this=this)
4842        return this
4843
4844    def _parse_window(
4845        self, this: t.Optional[exp.Expression], alias: bool = False
4846    ) -> t.Optional[exp.Expression]:
4847        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
4848            self._match(TokenType.WHERE)
4849            this = self.expression(
4850                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
4851            )
4852            self._match_r_paren()
4853
4854        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
4855        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
4856        if self._match_text_seq("WITHIN", "GROUP"):
4857            order = self._parse_wrapped(self._parse_order)
4858            this = self.expression(exp.WithinGroup, this=this, expression=order)
4859
4860        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
4861        # Some dialects choose to implement and some do not.
4862        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
4863
4864        # There is some code above in _parse_lambda that handles
4865        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
4866
4867        # The below changes handle
4868        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
4869
4870        # Oracle allows both formats
4871        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
4872        #   and Snowflake chose to do the same for familiarity
4873        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
4874        this = self._parse_respect_or_ignore_nulls(this)
4875
4876        # bigquery select from window x AS (partition by ...)
4877        if alias:
4878            over = None
4879            self._match(TokenType.ALIAS)
4880        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
4881            return this
4882        else:
4883            over = self._prev.text.upper()
4884
4885        if not self._match(TokenType.L_PAREN):
4886            return self.expression(
4887                exp.Window, this=this, alias=self._parse_id_var(False), over=over
4888            )
4889
4890        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
4891
4892        first = self._match(TokenType.FIRST)
4893        if self._match_text_seq("LAST"):
4894            first = False
4895
4896        partition, order = self._parse_partition_and_order()
4897        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
4898
4899        if kind:
4900            self._match(TokenType.BETWEEN)
4901            start = self._parse_window_spec()
4902            self._match(TokenType.AND)
4903            end = self._parse_window_spec()
4904
4905            spec = self.expression(
4906                exp.WindowSpec,
4907                kind=kind,
4908                start=start["value"],
4909                start_side=start["side"],
4910                end=end["value"],
4911                end_side=end["side"],
4912            )
4913        else:
4914            spec = None
4915
4916        self._match_r_paren()
4917
4918        window = self.expression(
4919            exp.Window,
4920            this=this,
4921            partition_by=partition,
4922            order=order,
4923            spec=spec,
4924            alias=window_alias,
4925            over=over,
4926            first=first,
4927        )
4928
4929        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
4930        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
4931            return self._parse_window(window, alias=alias)
4932
4933        return window
4934
4935    def _parse_partition_and_order(
4936        self,
4937    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
4938        return self._parse_partition_by(), self._parse_order()
4939
4940    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
4941        self._match(TokenType.BETWEEN)
4942
4943        return {
4944            "value": (
4945                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
4946                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
4947                or self._parse_bitwise()
4948            ),
4949            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
4950        }
4951
4952    def _parse_alias(
4953        self, this: t.Optional[exp.Expression], explicit: bool = False
4954    ) -> t.Optional[exp.Expression]:
4955        any_token = self._match(TokenType.ALIAS)
4956        comments = self._prev_comments
4957
4958        if explicit and not any_token:
4959            return this
4960
4961        if self._match(TokenType.L_PAREN):
4962            aliases = self.expression(
4963                exp.Aliases,
4964                comments=comments,
4965                this=this,
4966                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
4967            )
4968            self._match_r_paren(aliases)
4969            return aliases
4970
4971        alias = self._parse_id_var(any_token) or (
4972            self.STRING_ALIASES and self._parse_string_as_identifier()
4973        )
4974
4975        if alias:
4976            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
4977
4978            # Moves the comment next to the alias in `expr /* comment */ AS alias`
4979            if not this.comments and this.this.comments:
4980                this.comments = this.this.comments
4981                this.this.comments = None
4982
4983        return this
4984
4985    def _parse_id_var(
4986        self,
4987        any_token: bool = True,
4988        tokens: t.Optional[t.Collection[TokenType]] = None,
4989    ) -> t.Optional[exp.Expression]:
4990        identifier = self._parse_identifier()
4991
4992        if identifier:
4993            return identifier
4994
4995        if (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS):
4996            quoted = self._prev.token_type == TokenType.STRING
4997            return exp.Identifier(this=self._prev.text, quoted=quoted)
4998
4999        return None
5000
5001    def _parse_string(self) -> t.Optional[exp.Expression]:
5002        if self._match_set((TokenType.STRING, TokenType.RAW_STRING)):
5003            return self.PRIMARY_PARSERS[self._prev.token_type](self, self._prev)
5004        return self._parse_placeholder()
5005
5006    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
5007        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
5008
5009    def _parse_number(self) -> t.Optional[exp.Expression]:
5010        if self._match(TokenType.NUMBER):
5011            return self.PRIMARY_PARSERS[TokenType.NUMBER](self, self._prev)
5012        return self._parse_placeholder()
5013
5014    def _parse_identifier(self) -> t.Optional[exp.Expression]:
5015        if self._match(TokenType.IDENTIFIER):
5016            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
5017        return self._parse_placeholder()
5018
5019    def _parse_var(
5020        self,
5021        any_token: bool = False,
5022        tokens: t.Optional[t.Collection[TokenType]] = None,
5023        upper: bool = False,
5024    ) -> t.Optional[exp.Expression]:
5025        if (
5026            (any_token and self._advance_any())
5027            or self._match(TokenType.VAR)
5028            or (self._match_set(tokens) if tokens else False)
5029        ):
5030            return self.expression(
5031                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
5032            )
5033        return self._parse_placeholder()
5034
5035    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
5036        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
5037            self._advance()
5038            return self._prev
5039        return None
5040
5041    def _parse_var_or_string(self) -> t.Optional[exp.Expression]:
5042        return self._parse_var() or self._parse_string()
5043
5044    def _parse_null(self) -> t.Optional[exp.Expression]:
5045        if self._match_set(self.NULL_TOKENS):
5046            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
5047        return self._parse_placeholder()
5048
5049    def _parse_boolean(self) -> t.Optional[exp.Expression]:
5050        if self._match(TokenType.TRUE):
5051            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
5052        if self._match(TokenType.FALSE):
5053            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
5054        return self._parse_placeholder()
5055
5056    def _parse_star(self) -> t.Optional[exp.Expression]:
5057        if self._match(TokenType.STAR):
5058            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
5059        return self._parse_placeholder()
5060
5061    def _parse_parameter(self) -> exp.Parameter:
5062        def _parse_parameter_part() -> t.Optional[exp.Expression]:
5063            return (
5064                self._parse_identifier() or self._parse_primary() or self._parse_var(any_token=True)
5065            )
5066
5067        self._match(TokenType.L_BRACE)
5068        this = _parse_parameter_part()
5069        expression = self._match(TokenType.COLON) and _parse_parameter_part()
5070        self._match(TokenType.R_BRACE)
5071
5072        return self.expression(exp.Parameter, this=this, expression=expression)
5073
5074    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
5075        if self._match_set(self.PLACEHOLDER_PARSERS):
5076            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
5077            if placeholder:
5078                return placeholder
5079            self._advance(-1)
5080        return None
5081
5082    def _parse_except(self) -> t.Optional[t.List[exp.Expression]]:
5083        if not self._match(TokenType.EXCEPT):
5084            return None
5085        if self._match(TokenType.L_PAREN, advance=False):
5086            return self._parse_wrapped_csv(self._parse_column)
5087
5088        except_column = self._parse_column()
5089        return [except_column] if except_column else None
5090
5091    def _parse_replace(self) -> t.Optional[t.List[exp.Expression]]:
5092        if not self._match(TokenType.REPLACE):
5093            return None
5094        if self._match(TokenType.L_PAREN, advance=False):
5095            return self._parse_wrapped_csv(self._parse_expression)
5096
5097        replace_expression = self._parse_expression()
5098        return [replace_expression] if replace_expression else None
5099
5100    def _parse_csv(
5101        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
5102    ) -> t.List[exp.Expression]:
5103        parse_result = parse_method()
5104        items = [parse_result] if parse_result is not None else []
5105
5106        while self._match(sep):
5107            self._add_comments(parse_result)
5108            parse_result = parse_method()
5109            if parse_result is not None:
5110                items.append(parse_result)
5111
5112        return items
5113
5114    def _parse_tokens(
5115        self, parse_method: t.Callable, expressions: t.Dict
5116    ) -> t.Optional[exp.Expression]:
5117        this = parse_method()
5118
5119        while self._match_set(expressions):
5120            this = self.expression(
5121                expressions[self._prev.token_type],
5122                this=this,
5123                comments=self._prev_comments,
5124                expression=parse_method(),
5125            )
5126
5127        return this
5128
5129    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
5130        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
5131
5132    def _parse_wrapped_csv(
5133        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
5134    ) -> t.List[exp.Expression]:
5135        return self._parse_wrapped(
5136            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
5137        )
5138
5139    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
5140        wrapped = self._match(TokenType.L_PAREN)
5141        if not wrapped and not optional:
5142            self.raise_error("Expecting (")
5143        parse_result = parse_method()
5144        if wrapped:
5145            self._match_r_paren()
5146        return parse_result
5147
5148    def _parse_expressions(self) -> t.List[exp.Expression]:
5149        return self._parse_csv(self._parse_expression)
5150
5151    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
5152        return self._parse_select() or self._parse_set_operations(
5153            self._parse_expression() if alias else self._parse_conjunction()
5154        )
5155
5156    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
5157        return self._parse_query_modifiers(
5158            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
5159        )
5160
5161    def _parse_transaction(self) -> exp.Transaction | exp.Command:
5162        this = None
5163        if self._match_texts(self.TRANSACTION_KIND):
5164            this = self._prev.text
5165
5166        self._match_texts(("TRANSACTION", "WORK"))
5167
5168        modes = []
5169        while True:
5170            mode = []
5171            while self._match(TokenType.VAR):
5172                mode.append(self._prev.text)
5173
5174            if mode:
5175                modes.append(" ".join(mode))
5176            if not self._match(TokenType.COMMA):
5177                break
5178
5179        return self.expression(exp.Transaction, this=this, modes=modes)
5180
5181    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
5182        chain = None
5183        savepoint = None
5184        is_rollback = self._prev.token_type == TokenType.ROLLBACK
5185
5186        self._match_texts(("TRANSACTION", "WORK"))
5187
5188        if self._match_text_seq("TO"):
5189            self._match_text_seq("SAVEPOINT")
5190            savepoint = self._parse_id_var()
5191
5192        if self._match(TokenType.AND):
5193            chain = not self._match_text_seq("NO")
5194            self._match_text_seq("CHAIN")
5195
5196        if is_rollback:
5197            return self.expression(exp.Rollback, savepoint=savepoint)
5198
5199        return self.expression(exp.Commit, chain=chain)
5200
5201    def _parse_refresh(self) -> exp.Refresh:
5202        self._match(TokenType.TABLE)
5203        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
5204
5205    def _parse_add_column(self) -> t.Optional[exp.Expression]:
5206        if not self._match_text_seq("ADD"):
5207            return None
5208
5209        self._match(TokenType.COLUMN)
5210        exists_column = self._parse_exists(not_=True)
5211        expression = self._parse_field_def()
5212
5213        if expression:
5214            expression.set("exists", exists_column)
5215
5216            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
5217            if self._match_texts(("FIRST", "AFTER")):
5218                position = self._prev.text
5219                column_position = self.expression(
5220                    exp.ColumnPosition, this=self._parse_column(), position=position
5221                )
5222                expression.set("position", column_position)
5223
5224        return expression
5225
5226    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
5227        drop = self._match(TokenType.DROP) and self._parse_drop()
5228        if drop and not isinstance(drop, exp.Command):
5229            drop.set("kind", drop.args.get("kind", "COLUMN"))
5230        return drop
5231
5232    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
5233    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
5234        return self.expression(
5235            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
5236        )
5237
5238    def _parse_add_constraint(self) -> exp.AddConstraint:
5239        this = None
5240        kind = self._prev.token_type
5241
5242        if kind == TokenType.CONSTRAINT:
5243            this = self._parse_id_var()
5244
5245            if self._match_text_seq("CHECK"):
5246                expression = self._parse_wrapped(self._parse_conjunction)
5247                enforced = self._match_text_seq("ENFORCED")
5248
5249                return self.expression(
5250                    exp.AddConstraint, this=this, expression=expression, enforced=enforced
5251                )
5252
5253        if kind == TokenType.FOREIGN_KEY or self._match(TokenType.FOREIGN_KEY):
5254            expression = self._parse_foreign_key()
5255        elif kind == TokenType.PRIMARY_KEY or self._match(TokenType.PRIMARY_KEY):
5256            expression = self._parse_primary_key()
5257        else:
5258            expression = None
5259
5260        return self.expression(exp.AddConstraint, this=this, expression=expression)
5261
5262    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
5263        index = self._index - 1
5264
5265        if self._match_set(self.ADD_CONSTRAINT_TOKENS):
5266            return self._parse_csv(self._parse_add_constraint)
5267
5268        self._retreat(index)
5269        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
5270            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
5271        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
5272
5273    def _parse_alter_table_alter(self) -> exp.AlterColumn:
5274        self._match(TokenType.COLUMN)
5275        column = self._parse_field(any_token=True)
5276
5277        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
5278            return self.expression(exp.AlterColumn, this=column, drop=True)
5279        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
5280            return self.expression(exp.AlterColumn, this=column, default=self._parse_conjunction())
5281
5282        self._match_text_seq("SET", "DATA")
5283        return self.expression(
5284            exp.AlterColumn,
5285            this=column,
5286            dtype=self._match_text_seq("TYPE") and self._parse_types(),
5287            collate=self._match(TokenType.COLLATE) and self._parse_term(),
5288            using=self._match(TokenType.USING) and self._parse_conjunction(),
5289        )
5290
5291    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
5292        index = self._index - 1
5293
5294        partition_exists = self._parse_exists()
5295        if self._match(TokenType.PARTITION, advance=False):
5296            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
5297
5298        self._retreat(index)
5299        return self._parse_csv(self._parse_drop_column)
5300
5301    def _parse_alter_table_rename(self) -> exp.RenameTable:
5302        self._match_text_seq("TO")
5303        return self.expression(exp.RenameTable, this=self._parse_table(schema=True))
5304
5305    def _parse_alter(self) -> exp.AlterTable | exp.Command:
5306        start = self._prev
5307
5308        if not self._match(TokenType.TABLE):
5309            return self._parse_as_command(start)
5310
5311        exists = self._parse_exists()
5312        only = self._match_text_seq("ONLY")
5313        this = self._parse_table(schema=True)
5314
5315        if self._next:
5316            self._advance()
5317
5318        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
5319        if parser:
5320            actions = ensure_list(parser(self))
5321
5322            if not self._curr:
5323                return self.expression(
5324                    exp.AlterTable,
5325                    this=this,
5326                    exists=exists,
5327                    actions=actions,
5328                    only=only,
5329                )
5330
5331        return self._parse_as_command(start)
5332
5333    def _parse_merge(self) -> exp.Merge:
5334        self._match(TokenType.INTO)
5335        target = self._parse_table()
5336
5337        if target and self._match(TokenType.ALIAS, advance=False):
5338            target.set("alias", self._parse_table_alias())
5339
5340        self._match(TokenType.USING)
5341        using = self._parse_table()
5342
5343        self._match(TokenType.ON)
5344        on = self._parse_conjunction()
5345
5346        return self.expression(
5347            exp.Merge,
5348            this=target,
5349            using=using,
5350            on=on,
5351            expressions=self._parse_when_matched(),
5352        )
5353
5354    def _parse_when_matched(self) -> t.List[exp.When]:
5355        whens = []
5356
5357        while self._match(TokenType.WHEN):
5358            matched = not self._match(TokenType.NOT)
5359            self._match_text_seq("MATCHED")
5360            source = (
5361                False
5362                if self._match_text_seq("BY", "TARGET")
5363                else self._match_text_seq("BY", "SOURCE")
5364            )
5365            condition = self._parse_conjunction() if self._match(TokenType.AND) else None
5366
5367            self._match(TokenType.THEN)
5368
5369            if self._match(TokenType.INSERT):
5370                _this = self._parse_star()
5371                if _this:
5372                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=_this)
5373                else:
5374                    then = self.expression(
5375                        exp.Insert,
5376                        this=self._parse_value(),
5377                        expression=self._match(TokenType.VALUES) and self._parse_value(),
5378                    )
5379            elif self._match(TokenType.UPDATE):
5380                expressions = self._parse_star()
5381                if expressions:
5382                    then = self.expression(exp.Update, expressions=expressions)
5383                else:
5384                    then = self.expression(
5385                        exp.Update,
5386                        expressions=self._match(TokenType.SET)
5387                        and self._parse_csv(self._parse_equality),
5388                    )
5389            elif self._match(TokenType.DELETE):
5390                then = self.expression(exp.Var, this=self._prev.text)
5391            else:
5392                then = None
5393
5394            whens.append(
5395                self.expression(
5396                    exp.When,
5397                    matched=matched,
5398                    source=source,
5399                    condition=condition,
5400                    then=then,
5401                )
5402            )
5403        return whens
5404
5405    def _parse_show(self) -> t.Optional[exp.Expression]:
5406        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
5407        if parser:
5408            return parser(self)
5409        return self._parse_as_command(self._prev)
5410
5411    def _parse_set_item_assignment(
5412        self, kind: t.Optional[str] = None
5413    ) -> t.Optional[exp.Expression]:
5414        index = self._index
5415
5416        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
5417            return self._parse_set_transaction(global_=kind == "GLOBAL")
5418
5419        left = self._parse_primary() or self._parse_id_var()
5420        assignment_delimiter = self._match_texts(("=", "TO"))
5421
5422        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
5423            self._retreat(index)
5424            return None
5425
5426        right = self._parse_statement() or self._parse_id_var()
5427        this = self.expression(exp.EQ, this=left, expression=right)
5428
5429        return self.expression(exp.SetItem, this=this, kind=kind)
5430
5431    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
5432        self._match_text_seq("TRANSACTION")
5433        characteristics = self._parse_csv(
5434            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
5435        )
5436        return self.expression(
5437            exp.SetItem,
5438            expressions=characteristics,
5439            kind="TRANSACTION",
5440            **{"global": global_},  # type: ignore
5441        )
5442
5443    def _parse_set_item(self) -> t.Optional[exp.Expression]:
5444        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
5445        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
5446
5447    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
5448        index = self._index
5449        set_ = self.expression(
5450            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
5451        )
5452
5453        if self._curr:
5454            self._retreat(index)
5455            return self._parse_as_command(self._prev)
5456
5457        return set_
5458
5459    def _parse_var_from_options(self, options: t.Collection[str]) -> t.Optional[exp.Var]:
5460        for option in options:
5461            if self._match_text_seq(*option.split(" ")):
5462                return exp.var(option)
5463        return None
5464
5465    def _parse_as_command(self, start: Token) -> exp.Command:
5466        while self._curr:
5467            self._advance()
5468        text = self._find_sql(start, self._prev)
5469        size = len(start.text)
5470        return exp.Command(this=text[:size], expression=text[size:])
5471
5472    def _parse_dict_property(self, this: str) -> exp.DictProperty:
5473        settings = []
5474
5475        self._match_l_paren()
5476        kind = self._parse_id_var()
5477
5478        if self._match(TokenType.L_PAREN):
5479            while True:
5480                key = self._parse_id_var()
5481                value = self._parse_primary()
5482
5483                if not key and value is None:
5484                    break
5485                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
5486            self._match(TokenType.R_PAREN)
5487
5488        self._match_r_paren()
5489
5490        return self.expression(
5491            exp.DictProperty,
5492            this=this,
5493            kind=kind.this if kind else None,
5494            settings=settings,
5495        )
5496
5497    def _parse_dict_range(self, this: str) -> exp.DictRange:
5498        self._match_l_paren()
5499        has_min = self._match_text_seq("MIN")
5500        if has_min:
5501            min = self._parse_var() or self._parse_primary()
5502            self._match_text_seq("MAX")
5503            max = self._parse_var() or self._parse_primary()
5504        else:
5505            max = self._parse_var() or self._parse_primary()
5506            min = exp.Literal.number(0)
5507        self._match_r_paren()
5508        return self.expression(exp.DictRange, this=this, min=min, max=max)
5509
5510    def _parse_comprehension(
5511        self, this: t.Optional[exp.Expression]
5512    ) -> t.Optional[exp.Comprehension]:
5513        index = self._index
5514        expression = self._parse_column()
5515        if not self._match(TokenType.IN):
5516            self._retreat(index - 1)
5517            return None
5518        iterator = self._parse_column()
5519        condition = self._parse_conjunction() if self._match_text_seq("IF") else None
5520        return self.expression(
5521            exp.Comprehension,
5522            this=this,
5523            expression=expression,
5524            iterator=iterator,
5525            condition=condition,
5526        )
5527
5528    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
5529        if self._match(TokenType.HEREDOC_STRING):
5530            return self.expression(exp.Heredoc, this=self._prev.text)
5531
5532        if not self._match_text_seq("$"):
5533            return None
5534
5535        tags = ["$"]
5536        tag_text = None
5537
5538        if self._is_connected():
5539            self._advance()
5540            tags.append(self._prev.text.upper())
5541        else:
5542            self.raise_error("No closing $ found")
5543
5544        if tags[-1] != "$":
5545            if self._is_connected() and self._match_text_seq("$"):
5546                tag_text = tags[-1]
5547                tags.append("$")
5548            else:
5549                self.raise_error("No closing $ found")
5550
5551        heredoc_start = self._curr
5552
5553        while self._curr:
5554            if self._match_text_seq(*tags, advance=False):
5555                this = self._find_sql(heredoc_start, self._prev)
5556                self._advance(len(tags))
5557                return self.expression(exp.Heredoc, this=this, tag=tag_text)
5558
5559            self._advance()
5560
5561        self.raise_error(f"No closing {''.join(tags)} found")
5562        return None
5563
5564    def _find_parser(
5565        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
5566    ) -> t.Optional[t.Callable]:
5567        if not self._curr:
5568            return None
5569
5570        index = self._index
5571        this = []
5572        while True:
5573            # The current token might be multiple words
5574            curr = self._curr.text.upper()
5575            key = curr.split(" ")
5576            this.append(curr)
5577
5578            self._advance()
5579            result, trie = in_trie(trie, key)
5580            if result == TrieResult.FAILED:
5581                break
5582
5583            if result == TrieResult.EXISTS:
5584                subparser = parsers[" ".join(this)]
5585                return subparser
5586
5587        self._retreat(index)
5588        return None
5589
5590    def _match(self, token_type, advance=True, expression=None):
5591        if not self._curr:
5592            return None
5593
5594        if self._curr.token_type == token_type:
5595            if advance:
5596                self._advance()
5597            self._add_comments(expression)
5598            return True
5599
5600        return None
5601
5602    def _match_set(self, types, advance=True):
5603        if not self._curr:
5604            return None
5605
5606        if self._curr.token_type in types:
5607            if advance:
5608                self._advance()
5609            return True
5610
5611        return None
5612
5613    def _match_pair(self, token_type_a, token_type_b, advance=True):
5614        if not self._curr or not self._next:
5615            return None
5616
5617        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
5618            if advance:
5619                self._advance(2)
5620            return True
5621
5622        return None
5623
5624    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
5625        if not self._match(TokenType.L_PAREN, expression=expression):
5626            self.raise_error("Expecting (")
5627
5628    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
5629        if not self._match(TokenType.R_PAREN, expression=expression):
5630            self.raise_error("Expecting )")
5631
5632    def _match_texts(self, texts, advance=True):
5633        if self._curr and self._curr.text.upper() in texts:
5634            if advance:
5635                self._advance()
5636            return True
5637        return False
5638
5639    def _match_text_seq(self, *texts, advance=True):
5640        index = self._index
5641        for text in texts:
5642            if self._curr and self._curr.text.upper() == text:
5643                self._advance()
5644            else:
5645                self._retreat(index)
5646                return False
5647
5648        if not advance:
5649            self._retreat(index)
5650
5651        return True
5652
5653    @t.overload
5654    def _replace_columns_with_dots(self, this: exp.Expression) -> exp.Expression:
5655        ...
5656
5657    @t.overload
5658    def _replace_columns_with_dots(
5659        self, this: t.Optional[exp.Expression]
5660    ) -> t.Optional[exp.Expression]:
5661        ...
5662
5663    def _replace_columns_with_dots(self, this):
5664        if isinstance(this, exp.Dot):
5665            exp.replace_children(this, self._replace_columns_with_dots)
5666        elif isinstance(this, exp.Column):
5667            exp.replace_children(this, self._replace_columns_with_dots)
5668            table = this.args.get("table")
5669            this = (
5670                self.expression(exp.Dot, this=table, expression=this.this) if table else this.this
5671            )
5672
5673        return this
5674
5675    def _replace_lambda(
5676        self, node: t.Optional[exp.Expression], lambda_variables: t.Set[str]
5677    ) -> t.Optional[exp.Expression]:
5678        if not node:
5679            return node
5680
5681        for column in node.find_all(exp.Column):
5682            if column.parts[0].name in lambda_variables:
5683                dot_or_id = column.to_dot() if column.table else column.this
5684                parent = column.parent
5685
5686                while isinstance(parent, exp.Dot):
5687                    if not isinstance(parent.parent, exp.Dot):
5688                        parent.replace(dot_or_id)
5689                        break
5690                    parent = parent.parent
5691                else:
5692                    if column is node:
5693                        node = dot_or_id
5694                    else:
5695                        column.replace(dot_or_id)
5696        return node
logger = <Logger sqlglot (WARNING)>
def parse_var_map(args: List) -> sqlglot.expressions.StarMap | sqlglot.expressions.VarMap:
24def parse_var_map(args: t.List) -> exp.StarMap | exp.VarMap:
25    if len(args) == 1 and args[0].is_star:
26        return exp.StarMap(this=args[0])
27
28    keys = []
29    values = []
30    for i in range(0, len(args), 2):
31        keys.append(args[i])
32        values.append(args[i + 1])
33
34    return exp.VarMap(
35        keys=exp.Array(expressions=keys),
36        values=exp.Array(expressions=values),
37    )
def parse_like(args: List) -> sqlglot.expressions.Escape | sqlglot.expressions.Like:
40def parse_like(args: t.List) -> exp.Escape | exp.Like:
41    like = exp.Like(this=seq_get(args, 1), expression=seq_get(args, 0))
42    return exp.Escape(this=like, expression=seq_get(args, 2)) if len(args) > 2 else like
def binary_range_parser( expr_type: Type[sqlglot.expressions.Expression]) -> Callable[[Parser, Optional[sqlglot.expressions.Expression]], Optional[sqlglot.expressions.Expression]]:
45def binary_range_parser(
46    expr_type: t.Type[exp.Expression],
47) -> t.Callable[[Parser, t.Optional[exp.Expression]], t.Optional[exp.Expression]]:
48    return lambda self, this: self._parse_escape(
49        self.expression(expr_type, this=this, expression=self._parse_bitwise())
50    )
def parse_logarithm( args: List, dialect: sqlglot.dialects.dialect.Dialect) -> sqlglot.expressions.Func:
53def parse_logarithm(args: t.List, dialect: Dialect) -> exp.Func:
54    # Default argument order is base, expression
55    this = seq_get(args, 0)
56    expression = seq_get(args, 1)
57
58    if expression:
59        if not dialect.LOG_BASE_FIRST:
60            this, expression = expression, this
61        return exp.Log(this=this, expression=expression)
62
63    return (exp.Ln if dialect.parser_class.LOG_DEFAULTS_TO_LN else exp.Log)(this=this)
class Parser:
  76class Parser(metaclass=_Parser):
  77    """
  78    Parser consumes a list of tokens produced by the Tokenizer and produces a parsed syntax tree.
  79
  80    Args:
  81        error_level: The desired error level.
  82            Default: ErrorLevel.IMMEDIATE
  83        error_message_context: Determines the amount of context to capture from a
  84            query string when displaying the error message (in number of characters).
  85            Default: 100
  86        max_errors: Maximum number of error messages to include in a raised ParseError.
  87            This is only relevant if error_level is ErrorLevel.RAISE.
  88            Default: 3
  89    """
  90
  91    FUNCTIONS: t.Dict[str, t.Callable] = {
  92        **{name: func.from_arg_list for name, func in exp.FUNCTION_BY_NAME.items()},
  93        "CONCAT": lambda args, dialect: exp.Concat(
  94            expressions=args,
  95            safe=not dialect.STRICT_STRING_CONCAT,
  96            coalesce=dialect.CONCAT_COALESCE,
  97        ),
  98        "CONCAT_WS": lambda args, dialect: exp.ConcatWs(
  99            expressions=args,
 100            safe=not dialect.STRICT_STRING_CONCAT,
 101            coalesce=dialect.CONCAT_COALESCE,
 102        ),
 103        "DATE_TO_DATE_STR": lambda args: exp.Cast(
 104            this=seq_get(args, 0),
 105            to=exp.DataType(this=exp.DataType.Type.TEXT),
 106        ),
 107        "GLOB": lambda args: exp.Glob(this=seq_get(args, 1), expression=seq_get(args, 0)),
 108        "LIKE": parse_like,
 109        "LOG": parse_logarithm,
 110        "TIME_TO_TIME_STR": lambda args: exp.Cast(
 111            this=seq_get(args, 0),
 112            to=exp.DataType(this=exp.DataType.Type.TEXT),
 113        ),
 114        "TS_OR_DS_TO_DATE_STR": lambda args: exp.Substring(
 115            this=exp.Cast(
 116                this=seq_get(args, 0),
 117                to=exp.DataType(this=exp.DataType.Type.TEXT),
 118            ),
 119            start=exp.Literal.number(1),
 120            length=exp.Literal.number(10),
 121        ),
 122        "VAR_MAP": parse_var_map,
 123    }
 124
 125    NO_PAREN_FUNCTIONS = {
 126        TokenType.CURRENT_DATE: exp.CurrentDate,
 127        TokenType.CURRENT_DATETIME: exp.CurrentDate,
 128        TokenType.CURRENT_TIME: exp.CurrentTime,
 129        TokenType.CURRENT_TIMESTAMP: exp.CurrentTimestamp,
 130        TokenType.CURRENT_USER: exp.CurrentUser,
 131    }
 132
 133    STRUCT_TYPE_TOKENS = {
 134        TokenType.NESTED,
 135        TokenType.STRUCT,
 136    }
 137
 138    NESTED_TYPE_TOKENS = {
 139        TokenType.ARRAY,
 140        TokenType.LOWCARDINALITY,
 141        TokenType.MAP,
 142        TokenType.NULLABLE,
 143        *STRUCT_TYPE_TOKENS,
 144    }
 145
 146    ENUM_TYPE_TOKENS = {
 147        TokenType.ENUM,
 148        TokenType.ENUM8,
 149        TokenType.ENUM16,
 150    }
 151
 152    TYPE_TOKENS = {
 153        TokenType.BIT,
 154        TokenType.BOOLEAN,
 155        TokenType.TINYINT,
 156        TokenType.UTINYINT,
 157        TokenType.SMALLINT,
 158        TokenType.USMALLINT,
 159        TokenType.INT,
 160        TokenType.UINT,
 161        TokenType.BIGINT,
 162        TokenType.UBIGINT,
 163        TokenType.INT128,
 164        TokenType.UINT128,
 165        TokenType.INT256,
 166        TokenType.UINT256,
 167        TokenType.MEDIUMINT,
 168        TokenType.UMEDIUMINT,
 169        TokenType.FIXEDSTRING,
 170        TokenType.FLOAT,
 171        TokenType.DOUBLE,
 172        TokenType.CHAR,
 173        TokenType.NCHAR,
 174        TokenType.VARCHAR,
 175        TokenType.NVARCHAR,
 176        TokenType.TEXT,
 177        TokenType.MEDIUMTEXT,
 178        TokenType.LONGTEXT,
 179        TokenType.MEDIUMBLOB,
 180        TokenType.LONGBLOB,
 181        TokenType.BINARY,
 182        TokenType.VARBINARY,
 183        TokenType.JSON,
 184        TokenType.JSONB,
 185        TokenType.INTERVAL,
 186        TokenType.TINYBLOB,
 187        TokenType.TINYTEXT,
 188        TokenType.TIME,
 189        TokenType.TIMETZ,
 190        TokenType.TIMESTAMP,
 191        TokenType.TIMESTAMP_S,
 192        TokenType.TIMESTAMP_MS,
 193        TokenType.TIMESTAMP_NS,
 194        TokenType.TIMESTAMPTZ,
 195        TokenType.TIMESTAMPLTZ,
 196        TokenType.DATETIME,
 197        TokenType.DATETIME64,
 198        TokenType.DATE,
 199        TokenType.DATE32,
 200        TokenType.INT4RANGE,
 201        TokenType.INT4MULTIRANGE,
 202        TokenType.INT8RANGE,
 203        TokenType.INT8MULTIRANGE,
 204        TokenType.NUMRANGE,
 205        TokenType.NUMMULTIRANGE,
 206        TokenType.TSRANGE,
 207        TokenType.TSMULTIRANGE,
 208        TokenType.TSTZRANGE,
 209        TokenType.TSTZMULTIRANGE,
 210        TokenType.DATERANGE,
 211        TokenType.DATEMULTIRANGE,
 212        TokenType.DECIMAL,
 213        TokenType.UDECIMAL,
 214        TokenType.BIGDECIMAL,
 215        TokenType.UUID,
 216        TokenType.GEOGRAPHY,
 217        TokenType.GEOMETRY,
 218        TokenType.HLLSKETCH,
 219        TokenType.HSTORE,
 220        TokenType.PSEUDO_TYPE,
 221        TokenType.SUPER,
 222        TokenType.SERIAL,
 223        TokenType.SMALLSERIAL,
 224        TokenType.BIGSERIAL,
 225        TokenType.XML,
 226        TokenType.YEAR,
 227        TokenType.UNIQUEIDENTIFIER,
 228        TokenType.USERDEFINED,
 229        TokenType.MONEY,
 230        TokenType.SMALLMONEY,
 231        TokenType.ROWVERSION,
 232        TokenType.IMAGE,
 233        TokenType.VARIANT,
 234        TokenType.OBJECT,
 235        TokenType.OBJECT_IDENTIFIER,
 236        TokenType.INET,
 237        TokenType.IPADDRESS,
 238        TokenType.IPPREFIX,
 239        TokenType.IPV4,
 240        TokenType.IPV6,
 241        TokenType.UNKNOWN,
 242        TokenType.NULL,
 243        *ENUM_TYPE_TOKENS,
 244        *NESTED_TYPE_TOKENS,
 245    }
 246
 247    SIGNED_TO_UNSIGNED_TYPE_TOKEN = {
 248        TokenType.BIGINT: TokenType.UBIGINT,
 249        TokenType.INT: TokenType.UINT,
 250        TokenType.MEDIUMINT: TokenType.UMEDIUMINT,
 251        TokenType.SMALLINT: TokenType.USMALLINT,
 252        TokenType.TINYINT: TokenType.UTINYINT,
 253        TokenType.DECIMAL: TokenType.UDECIMAL,
 254    }
 255
 256    SUBQUERY_PREDICATES = {
 257        TokenType.ANY: exp.Any,
 258        TokenType.ALL: exp.All,
 259        TokenType.EXISTS: exp.Exists,
 260        TokenType.SOME: exp.Any,
 261    }
 262
 263    RESERVED_TOKENS = {
 264        *Tokenizer.SINGLE_TOKENS.values(),
 265        TokenType.SELECT,
 266    }
 267
 268    DB_CREATABLES = {
 269        TokenType.DATABASE,
 270        TokenType.SCHEMA,
 271        TokenType.TABLE,
 272        TokenType.VIEW,
 273        TokenType.MODEL,
 274        TokenType.DICTIONARY,
 275    }
 276
 277    CREATABLES = {
 278        TokenType.COLUMN,
 279        TokenType.CONSTRAINT,
 280        TokenType.FUNCTION,
 281        TokenType.INDEX,
 282        TokenType.PROCEDURE,
 283        TokenType.FOREIGN_KEY,
 284        *DB_CREATABLES,
 285    }
 286
 287    # Tokens that can represent identifiers
 288    ID_VAR_TOKENS = {
 289        TokenType.VAR,
 290        TokenType.ANTI,
 291        TokenType.APPLY,
 292        TokenType.ASC,
 293        TokenType.AUTO_INCREMENT,
 294        TokenType.BEGIN,
 295        TokenType.CACHE,
 296        TokenType.CASE,
 297        TokenType.COLLATE,
 298        TokenType.COMMAND,
 299        TokenType.COMMENT,
 300        TokenType.COMMIT,
 301        TokenType.CONSTRAINT,
 302        TokenType.DEFAULT,
 303        TokenType.DELETE,
 304        TokenType.DESC,
 305        TokenType.DESCRIBE,
 306        TokenType.DICTIONARY,
 307        TokenType.DIV,
 308        TokenType.END,
 309        TokenType.EXECUTE,
 310        TokenType.ESCAPE,
 311        TokenType.FALSE,
 312        TokenType.FIRST,
 313        TokenType.FILTER,
 314        TokenType.FINAL,
 315        TokenType.FORMAT,
 316        TokenType.FULL,
 317        TokenType.IS,
 318        TokenType.ISNULL,
 319        TokenType.INTERVAL,
 320        TokenType.KEEP,
 321        TokenType.KILL,
 322        TokenType.LEFT,
 323        TokenType.LOAD,
 324        TokenType.MERGE,
 325        TokenType.NATURAL,
 326        TokenType.NEXT,
 327        TokenType.OFFSET,
 328        TokenType.OPERATOR,
 329        TokenType.ORDINALITY,
 330        TokenType.OVERLAPS,
 331        TokenType.OVERWRITE,
 332        TokenType.PARTITION,
 333        TokenType.PERCENT,
 334        TokenType.PIVOT,
 335        TokenType.PRAGMA,
 336        TokenType.RANGE,
 337        TokenType.RECURSIVE,
 338        TokenType.REFERENCES,
 339        TokenType.REFRESH,
 340        TokenType.REPLACE,
 341        TokenType.RIGHT,
 342        TokenType.ROW,
 343        TokenType.ROWS,
 344        TokenType.SEMI,
 345        TokenType.SET,
 346        TokenType.SETTINGS,
 347        TokenType.SHOW,
 348        TokenType.TEMPORARY,
 349        TokenType.TOP,
 350        TokenType.TRUE,
 351        TokenType.UNIQUE,
 352        TokenType.UNPIVOT,
 353        TokenType.UPDATE,
 354        TokenType.USE,
 355        TokenType.VOLATILE,
 356        TokenType.WINDOW,
 357        *CREATABLES,
 358        *SUBQUERY_PREDICATES,
 359        *TYPE_TOKENS,
 360        *NO_PAREN_FUNCTIONS,
 361    }
 362
 363    INTERVAL_VARS = ID_VAR_TOKENS - {TokenType.END}
 364
 365    TABLE_ALIAS_TOKENS = ID_VAR_TOKENS - {
 366        TokenType.ANTI,
 367        TokenType.APPLY,
 368        TokenType.ASOF,
 369        TokenType.FULL,
 370        TokenType.LEFT,
 371        TokenType.LOCK,
 372        TokenType.NATURAL,
 373        TokenType.OFFSET,
 374        TokenType.RIGHT,
 375        TokenType.SEMI,
 376        TokenType.WINDOW,
 377    }
 378
 379    COMMENT_TABLE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.IS}
 380
 381    UPDATE_ALIAS_TOKENS = TABLE_ALIAS_TOKENS - {TokenType.SET}
 382
 383    TRIM_TYPES = {"LEADING", "TRAILING", "BOTH"}
 384
 385    FUNC_TOKENS = {
 386        TokenType.COLLATE,
 387        TokenType.COMMAND,
 388        TokenType.CURRENT_DATE,
 389        TokenType.CURRENT_DATETIME,
 390        TokenType.CURRENT_TIMESTAMP,
 391        TokenType.CURRENT_TIME,
 392        TokenType.CURRENT_USER,
 393        TokenType.FILTER,
 394        TokenType.FIRST,
 395        TokenType.FORMAT,
 396        TokenType.GLOB,
 397        TokenType.IDENTIFIER,
 398        TokenType.INDEX,
 399        TokenType.ISNULL,
 400        TokenType.ILIKE,
 401        TokenType.INSERT,
 402        TokenType.LIKE,
 403        TokenType.MERGE,
 404        TokenType.OFFSET,
 405        TokenType.PRIMARY_KEY,
 406        TokenType.RANGE,
 407        TokenType.REPLACE,
 408        TokenType.RLIKE,
 409        TokenType.ROW,
 410        TokenType.UNNEST,
 411        TokenType.VAR,
 412        TokenType.LEFT,
 413        TokenType.RIGHT,
 414        TokenType.DATE,
 415        TokenType.DATETIME,
 416        TokenType.TABLE,
 417        TokenType.TIMESTAMP,
 418        TokenType.TIMESTAMPTZ,
 419        TokenType.WINDOW,
 420        TokenType.XOR,
 421        *TYPE_TOKENS,
 422        *SUBQUERY_PREDICATES,
 423    }
 424
 425    CONJUNCTION = {
 426        TokenType.AND: exp.And,
 427        TokenType.OR: exp.Or,
 428    }
 429
 430    EQUALITY = {
 431        TokenType.COLON_EQ: exp.PropertyEQ,
 432        TokenType.EQ: exp.EQ,
 433        TokenType.NEQ: exp.NEQ,
 434        TokenType.NULLSAFE_EQ: exp.NullSafeEQ,
 435    }
 436
 437    COMPARISON = {
 438        TokenType.GT: exp.GT,
 439        TokenType.GTE: exp.GTE,
 440        TokenType.LT: exp.LT,
 441        TokenType.LTE: exp.LTE,
 442    }
 443
 444    BITWISE = {
 445        TokenType.AMP: exp.BitwiseAnd,
 446        TokenType.CARET: exp.BitwiseXor,
 447        TokenType.PIPE: exp.BitwiseOr,
 448    }
 449
 450    TERM = {
 451        TokenType.DASH: exp.Sub,
 452        TokenType.PLUS: exp.Add,
 453        TokenType.MOD: exp.Mod,
 454        TokenType.COLLATE: exp.Collate,
 455    }
 456
 457    FACTOR = {
 458        TokenType.DIV: exp.IntDiv,
 459        TokenType.LR_ARROW: exp.Distance,
 460        TokenType.SLASH: exp.Div,
 461        TokenType.STAR: exp.Mul,
 462    }
 463
 464    EXPONENT: t.Dict[TokenType, t.Type[exp.Expression]] = {}
 465
 466    TIMES = {
 467        TokenType.TIME,
 468        TokenType.TIMETZ,
 469    }
 470
 471    TIMESTAMPS = {
 472        TokenType.TIMESTAMP,
 473        TokenType.TIMESTAMPTZ,
 474        TokenType.TIMESTAMPLTZ,
 475        *TIMES,
 476    }
 477
 478    SET_OPERATIONS = {
 479        TokenType.UNION,
 480        TokenType.INTERSECT,
 481        TokenType.EXCEPT,
 482    }
 483
 484    JOIN_METHODS = {
 485        TokenType.NATURAL,
 486        TokenType.ASOF,
 487    }
 488
 489    JOIN_SIDES = {
 490        TokenType.LEFT,
 491        TokenType.RIGHT,
 492        TokenType.FULL,
 493    }
 494
 495    JOIN_KINDS = {
 496        TokenType.INNER,
 497        TokenType.OUTER,
 498        TokenType.CROSS,
 499        TokenType.SEMI,
 500        TokenType.ANTI,
 501    }
 502
 503    JOIN_HINTS: t.Set[str] = set()
 504
 505    LAMBDAS = {
 506        TokenType.ARROW: lambda self, expressions: self.expression(
 507            exp.Lambda,
 508            this=self._replace_lambda(
 509                self._parse_conjunction(),
 510                {node.name for node in expressions},
 511            ),
 512            expressions=expressions,
 513        ),
 514        TokenType.FARROW: lambda self, expressions: self.expression(
 515            exp.Kwarg,
 516            this=exp.var(expressions[0].name),
 517            expression=self._parse_conjunction(),
 518        ),
 519    }
 520
 521    COLUMN_OPERATORS = {
 522        TokenType.DOT: None,
 523        TokenType.DCOLON: lambda self, this, to: self.expression(
 524            exp.Cast if self.STRICT_CAST else exp.TryCast,
 525            this=this,
 526            to=to,
 527        ),
 528        TokenType.ARROW: lambda self, this, path: self.expression(
 529            exp.JSONExtract,
 530            this=this,
 531            expression=path,
 532        ),
 533        TokenType.DARROW: lambda self, this, path: self.expression(
 534            exp.JSONExtractScalar,
 535            this=this,
 536            expression=path,
 537        ),
 538        TokenType.HASH_ARROW: lambda self, this, path: self.expression(
 539            exp.JSONBExtract,
 540            this=this,
 541            expression=path,
 542        ),
 543        TokenType.DHASH_ARROW: lambda self, this, path: self.expression(
 544            exp.JSONBExtractScalar,
 545            this=this,
 546            expression=path,
 547        ),
 548        TokenType.PLACEHOLDER: lambda self, this, key: self.expression(
 549            exp.JSONBContains,
 550            this=this,
 551            expression=key,
 552        ),
 553    }
 554
 555    EXPRESSION_PARSERS = {
 556        exp.Cluster: lambda self: self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
 557        exp.Column: lambda self: self._parse_column(),
 558        exp.Condition: lambda self: self._parse_conjunction(),
 559        exp.DataType: lambda self: self._parse_types(allow_identifiers=False),
 560        exp.Expression: lambda self: self._parse_statement(),
 561        exp.From: lambda self: self._parse_from(),
 562        exp.Group: lambda self: self._parse_group(),
 563        exp.Having: lambda self: self._parse_having(),
 564        exp.Identifier: lambda self: self._parse_id_var(),
 565        exp.Join: lambda self: self._parse_join(),
 566        exp.Lambda: lambda self: self._parse_lambda(),
 567        exp.Lateral: lambda self: self._parse_lateral(),
 568        exp.Limit: lambda self: self._parse_limit(),
 569        exp.Offset: lambda self: self._parse_offset(),
 570        exp.Order: lambda self: self._parse_order(),
 571        exp.Ordered: lambda self: self._parse_ordered(),
 572        exp.Properties: lambda self: self._parse_properties(),
 573        exp.Qualify: lambda self: self._parse_qualify(),
 574        exp.Returning: lambda self: self._parse_returning(),
 575        exp.Sort: lambda self: self._parse_sort(exp.Sort, TokenType.SORT_BY),
 576        exp.Table: lambda self: self._parse_table_parts(),
 577        exp.TableAlias: lambda self: self._parse_table_alias(),
 578        exp.When: lambda self: seq_get(self._parse_when_matched(), 0),
 579        exp.Where: lambda self: self._parse_where(),
 580        exp.Window: lambda self: self._parse_named_window(),
 581        exp.With: lambda self: self._parse_with(),
 582        "JOIN_TYPE": lambda self: self._parse_join_parts(),
 583    }
 584
 585    STATEMENT_PARSERS = {
 586        TokenType.ALTER: lambda self: self._parse_alter(),
 587        TokenType.BEGIN: lambda self: self._parse_transaction(),
 588        TokenType.CACHE: lambda self: self._parse_cache(),
 589        TokenType.COMMIT: lambda self: self._parse_commit_or_rollback(),
 590        TokenType.COMMENT: lambda self: self._parse_comment(),
 591        TokenType.CREATE: lambda self: self._parse_create(),
 592        TokenType.DELETE: lambda self: self._parse_delete(),
 593        TokenType.DESC: lambda self: self._parse_describe(),
 594        TokenType.DESCRIBE: lambda self: self._parse_describe(),
 595        TokenType.DROP: lambda self: self._parse_drop(),
 596        TokenType.INSERT: lambda self: self._parse_insert(),
 597        TokenType.KILL: lambda self: self._parse_kill(),
 598        TokenType.LOAD: lambda self: self._parse_load(),
 599        TokenType.MERGE: lambda self: self._parse_merge(),
 600        TokenType.PIVOT: lambda self: self._parse_simplified_pivot(),
 601        TokenType.PRAGMA: lambda self: self.expression(exp.Pragma, this=self._parse_expression()),
 602        TokenType.REFRESH: lambda self: self._parse_refresh(),
 603        TokenType.ROLLBACK: lambda self: self._parse_commit_or_rollback(),
 604        TokenType.SET: lambda self: self._parse_set(),
 605        TokenType.UNCACHE: lambda self: self._parse_uncache(),
 606        TokenType.UPDATE: lambda self: self._parse_update(),
 607        TokenType.USE: lambda self: self.expression(
 608            exp.Use,
 609            kind=self._match_texts(("ROLE", "WAREHOUSE", "DATABASE", "SCHEMA"))
 610            and exp.var(self._prev.text),
 611            this=self._parse_table(schema=False),
 612        ),
 613    }
 614
 615    UNARY_PARSERS = {
 616        TokenType.PLUS: lambda self: self._parse_unary(),  # Unary + is handled as a no-op
 617        TokenType.NOT: lambda self: self.expression(exp.Not, this=self._parse_equality()),
 618        TokenType.TILDA: lambda self: self.expression(exp.BitwiseNot, this=self._parse_unary()),
 619        TokenType.DASH: lambda self: self.expression(exp.Neg, this=self._parse_unary()),
 620    }
 621
 622    PRIMARY_PARSERS = {
 623        TokenType.STRING: lambda self, token: self.expression(
 624            exp.Literal, this=token.text, is_string=True
 625        ),
 626        TokenType.NUMBER: lambda self, token: self.expression(
 627            exp.Literal, this=token.text, is_string=False
 628        ),
 629        TokenType.STAR: lambda self, _: self.expression(
 630            exp.Star, **{"except": self._parse_except(), "replace": self._parse_replace()}
 631        ),
 632        TokenType.NULL: lambda self, _: self.expression(exp.Null),
 633        TokenType.TRUE: lambda self, _: self.expression(exp.Boolean, this=True),
 634        TokenType.FALSE: lambda self, _: self.expression(exp.Boolean, this=False),
 635        TokenType.BIT_STRING: lambda self, token: self.expression(exp.BitString, this=token.text),
 636        TokenType.HEX_STRING: lambda self, token: self.expression(exp.HexString, this=token.text),
 637        TokenType.BYTE_STRING: lambda self, token: self.expression(exp.ByteString, this=token.text),
 638        TokenType.INTRODUCER: lambda self, token: self._parse_introducer(token),
 639        TokenType.NATIONAL_STRING: lambda self, token: self.expression(
 640            exp.National, this=token.text
 641        ),
 642        TokenType.RAW_STRING: lambda self, token: self.expression(exp.RawString, this=token.text),
 643        TokenType.HEREDOC_STRING: lambda self, token: self.expression(
 644            exp.RawString, this=token.text
 645        ),
 646        TokenType.UNICODE_STRING: lambda self, token: self.expression(
 647            exp.UnicodeString,
 648            this=token.text,
 649            escape=self._match_text_seq("UESCAPE") and self._parse_string(),
 650        ),
 651        TokenType.SESSION_PARAMETER: lambda self, _: self._parse_session_parameter(),
 652    }
 653
 654    PLACEHOLDER_PARSERS = {
 655        TokenType.PLACEHOLDER: lambda self: self.expression(exp.Placeholder),
 656        TokenType.PARAMETER: lambda self: self._parse_parameter(),
 657        TokenType.COLON: lambda self: self.expression(exp.Placeholder, this=self._prev.text)
 658        if self._match(TokenType.NUMBER) or self._match_set(self.ID_VAR_TOKENS)
 659        else None,
 660    }
 661
 662    RANGE_PARSERS = {
 663        TokenType.BETWEEN: lambda self, this: self._parse_between(this),
 664        TokenType.GLOB: binary_range_parser(exp.Glob),
 665        TokenType.ILIKE: binary_range_parser(exp.ILike),
 666        TokenType.IN: lambda self, this: self._parse_in(this),
 667        TokenType.IRLIKE: binary_range_parser(exp.RegexpILike),
 668        TokenType.IS: lambda self, this: self._parse_is(this),
 669        TokenType.LIKE: binary_range_parser(exp.Like),
 670        TokenType.OVERLAPS: binary_range_parser(exp.Overlaps),
 671        TokenType.RLIKE: binary_range_parser(exp.RegexpLike),
 672        TokenType.SIMILAR_TO: binary_range_parser(exp.SimilarTo),
 673        TokenType.FOR: lambda self, this: self._parse_comprehension(this),
 674    }
 675
 676    PROPERTY_PARSERS: t.Dict[str, t.Callable] = {
 677        "ALGORITHM": lambda self: self._parse_property_assignment(exp.AlgorithmProperty),
 678        "AUTO": lambda self: self._parse_auto_property(),
 679        "AUTO_INCREMENT": lambda self: self._parse_property_assignment(exp.AutoIncrementProperty),
 680        "BLOCKCOMPRESSION": lambda self: self._parse_blockcompression(),
 681        "CHARSET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 682        "CHARACTER SET": lambda self, **kwargs: self._parse_character_set(**kwargs),
 683        "CHECKSUM": lambda self: self._parse_checksum(),
 684        "CLUSTER BY": lambda self: self._parse_cluster(),
 685        "CLUSTERED": lambda self: self._parse_clustered_by(),
 686        "COLLATE": lambda self, **kwargs: self._parse_property_assignment(
 687            exp.CollateProperty, **kwargs
 688        ),
 689        "COMMENT": lambda self: self._parse_property_assignment(exp.SchemaCommentProperty),
 690        "CONTAINS": lambda self: self._parse_contains_property(),
 691        "COPY": lambda self: self._parse_copy_property(),
 692        "DATABLOCKSIZE": lambda self, **kwargs: self._parse_datablocksize(**kwargs),
 693        "DEFINER": lambda self: self._parse_definer(),
 694        "DETERMINISTIC": lambda self: self.expression(
 695            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 696        ),
 697        "DISTKEY": lambda self: self._parse_distkey(),
 698        "DISTSTYLE": lambda self: self._parse_property_assignment(exp.DistStyleProperty),
 699        "ENGINE": lambda self: self._parse_property_assignment(exp.EngineProperty),
 700        "EXECUTE": lambda self: self._parse_property_assignment(exp.ExecuteAsProperty),
 701        "EXTERNAL": lambda self: self.expression(exp.ExternalProperty),
 702        "FALLBACK": lambda self, **kwargs: self._parse_fallback(**kwargs),
 703        "FORMAT": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 704        "FREESPACE": lambda self: self._parse_freespace(),
 705        "HEAP": lambda self: self.expression(exp.HeapProperty),
 706        "IMMUTABLE": lambda self: self.expression(
 707            exp.StabilityProperty, this=exp.Literal.string("IMMUTABLE")
 708        ),
 709        "INPUT": lambda self: self.expression(exp.InputModelProperty, this=self._parse_schema()),
 710        "JOURNAL": lambda self, **kwargs: self._parse_journal(**kwargs),
 711        "LANGUAGE": lambda self: self._parse_property_assignment(exp.LanguageProperty),
 712        "LAYOUT": lambda self: self._parse_dict_property(this="LAYOUT"),
 713        "LIFETIME": lambda self: self._parse_dict_range(this="LIFETIME"),
 714        "LIKE": lambda self: self._parse_create_like(),
 715        "LOCATION": lambda self: self._parse_property_assignment(exp.LocationProperty),
 716        "LOCK": lambda self: self._parse_locking(),
 717        "LOCKING": lambda self: self._parse_locking(),
 718        "LOG": lambda self, **kwargs: self._parse_log(**kwargs),
 719        "MATERIALIZED": lambda self: self.expression(exp.MaterializedProperty),
 720        "MERGEBLOCKRATIO": lambda self, **kwargs: self._parse_mergeblockratio(**kwargs),
 721        "MODIFIES": lambda self: self._parse_modifies_property(),
 722        "MULTISET": lambda self: self.expression(exp.SetProperty, multi=True),
 723        "NO": lambda self: self._parse_no_property(),
 724        "ON": lambda self: self._parse_on_property(),
 725        "ORDER BY": lambda self: self._parse_order(skip_order_token=True),
 726        "OUTPUT": lambda self: self.expression(exp.OutputModelProperty, this=self._parse_schema()),
 727        "PARTITION": lambda self: self._parse_partitioned_of(),
 728        "PARTITION BY": lambda self: self._parse_partitioned_by(),
 729        "PARTITIONED BY": lambda self: self._parse_partitioned_by(),
 730        "PARTITIONED_BY": lambda self: self._parse_partitioned_by(),
 731        "PRIMARY KEY": lambda self: self._parse_primary_key(in_props=True),
 732        "RANGE": lambda self: self._parse_dict_range(this="RANGE"),
 733        "READS": lambda self: self._parse_reads_property(),
 734        "REMOTE": lambda self: self._parse_remote_with_connection(),
 735        "RETURNS": lambda self: self._parse_returns(),
 736        "ROW": lambda self: self._parse_row(),
 737        "ROW_FORMAT": lambda self: self._parse_property_assignment(exp.RowFormatProperty),
 738        "SAMPLE": lambda self: self.expression(
 739            exp.SampleProperty, this=self._match_text_seq("BY") and self._parse_bitwise()
 740        ),
 741        "SET": lambda self: self.expression(exp.SetProperty, multi=False),
 742        "SETTINGS": lambda self: self.expression(
 743            exp.SettingsProperty, expressions=self._parse_csv(self._parse_set_item)
 744        ),
 745        "SORTKEY": lambda self: self._parse_sortkey(),
 746        "SOURCE": lambda self: self._parse_dict_property(this="SOURCE"),
 747        "STABLE": lambda self: self.expression(
 748            exp.StabilityProperty, this=exp.Literal.string("STABLE")
 749        ),
 750        "STORED": lambda self: self._parse_stored(),
 751        "SYSTEM_VERSIONING": lambda self: self._parse_system_versioning_property(),
 752        "TBLPROPERTIES": lambda self: self._parse_wrapped_csv(self._parse_property),
 753        "TEMP": lambda self: self.expression(exp.TemporaryProperty),
 754        "TEMPORARY": lambda self: self.expression(exp.TemporaryProperty),
 755        "TO": lambda self: self._parse_to_table(),
 756        "TRANSIENT": lambda self: self.expression(exp.TransientProperty),
 757        "TRANSFORM": lambda self: self.expression(
 758            exp.TransformModelProperty, expressions=self._parse_wrapped_csv(self._parse_expression)
 759        ),
 760        "TTL": lambda self: self._parse_ttl(),
 761        "USING": lambda self: self._parse_property_assignment(exp.FileFormatProperty),
 762        "VOLATILE": lambda self: self._parse_volatile_property(),
 763        "WITH": lambda self: self._parse_with_property(),
 764    }
 765
 766    CONSTRAINT_PARSERS = {
 767        "AUTOINCREMENT": lambda self: self._parse_auto_increment(),
 768        "AUTO_INCREMENT": lambda self: self._parse_auto_increment(),
 769        "CASESPECIFIC": lambda self: self.expression(exp.CaseSpecificColumnConstraint, not_=False),
 770        "CHARACTER SET": lambda self: self.expression(
 771            exp.CharacterSetColumnConstraint, this=self._parse_var_or_string()
 772        ),
 773        "CHECK": lambda self: self.expression(
 774            exp.CheckColumnConstraint, this=self._parse_wrapped(self._parse_conjunction)
 775        ),
 776        "COLLATE": lambda self: self.expression(
 777            exp.CollateColumnConstraint, this=self._parse_var()
 778        ),
 779        "COMMENT": lambda self: self.expression(
 780            exp.CommentColumnConstraint, this=self._parse_string()
 781        ),
 782        "COMPRESS": lambda self: self._parse_compress(),
 783        "CLUSTERED": lambda self: self.expression(
 784            exp.ClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
 785        ),
 786        "NONCLUSTERED": lambda self: self.expression(
 787            exp.NonClusteredColumnConstraint, this=self._parse_wrapped_csv(self._parse_ordered)
 788        ),
 789        "DEFAULT": lambda self: self.expression(
 790            exp.DefaultColumnConstraint, this=self._parse_bitwise()
 791        ),
 792        "ENCODE": lambda self: self.expression(exp.EncodeColumnConstraint, this=self._parse_var()),
 793        "FOREIGN KEY": lambda self: self._parse_foreign_key(),
 794        "FORMAT": lambda self: self.expression(
 795            exp.DateFormatColumnConstraint, this=self._parse_var_or_string()
 796        ),
 797        "GENERATED": lambda self: self._parse_generated_as_identity(),
 798        "IDENTITY": lambda self: self._parse_auto_increment(),
 799        "INLINE": lambda self: self._parse_inline(),
 800        "LIKE": lambda self: self._parse_create_like(),
 801        "NOT": lambda self: self._parse_not_constraint(),
 802        "NULL": lambda self: self.expression(exp.NotNullColumnConstraint, allow_null=True),
 803        "ON": lambda self: (
 804            self._match(TokenType.UPDATE)
 805            and self.expression(exp.OnUpdateColumnConstraint, this=self._parse_function())
 806        )
 807        or self.expression(exp.OnProperty, this=self._parse_id_var()),
 808        "PATH": lambda self: self.expression(exp.PathColumnConstraint, this=self._parse_string()),
 809        "PERIOD": lambda self: self._parse_period_for_system_time(),
 810        "PRIMARY KEY": lambda self: self._parse_primary_key(),
 811        "REFERENCES": lambda self: self._parse_references(match=False),
 812        "TITLE": lambda self: self.expression(
 813            exp.TitleColumnConstraint, this=self._parse_var_or_string()
 814        ),
 815        "TTL": lambda self: self.expression(exp.MergeTreeTTL, expressions=[self._parse_bitwise()]),
 816        "UNIQUE": lambda self: self._parse_unique(),
 817        "UPPERCASE": lambda self: self.expression(exp.UppercaseColumnConstraint),
 818        "WITH": lambda self: self.expression(
 819            exp.Properties, expressions=self._parse_wrapped_csv(self._parse_property)
 820        ),
 821    }
 822
 823    ALTER_PARSERS = {
 824        "ADD": lambda self: self._parse_alter_table_add(),
 825        "ALTER": lambda self: self._parse_alter_table_alter(),
 826        "DELETE": lambda self: self.expression(exp.Delete, where=self._parse_where()),
 827        "DROP": lambda self: self._parse_alter_table_drop(),
 828        "RENAME": lambda self: self._parse_alter_table_rename(),
 829    }
 830
 831    SCHEMA_UNNAMED_CONSTRAINTS = {"CHECK", "FOREIGN KEY", "LIKE", "PRIMARY KEY", "UNIQUE", "PERIOD"}
 832
 833    NO_PAREN_FUNCTION_PARSERS = {
 834        "ANY": lambda self: self.expression(exp.Any, this=self._parse_bitwise()),
 835        "CASE": lambda self: self._parse_case(),
 836        "IF": lambda self: self._parse_if(),
 837        "NEXT": lambda self: self._parse_next_value_for(),
 838    }
 839
 840    INVALID_FUNC_NAME_TOKENS = {
 841        TokenType.IDENTIFIER,
 842        TokenType.STRING,
 843    }
 844
 845    FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
 846
 847    FUNCTION_PARSERS = {
 848        "ANY_VALUE": lambda self: self._parse_any_value(),
 849        "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
 850        "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
 851        "DECODE": lambda self: self._parse_decode(),
 852        "EXTRACT": lambda self: self._parse_extract(),
 853        "JSON_OBJECT": lambda self: self._parse_json_object(),
 854        "JSON_OBJECTAGG": lambda self: self._parse_json_object(agg=True),
 855        "JSON_TABLE": lambda self: self._parse_json_table(),
 856        "MATCH": lambda self: self._parse_match_against(),
 857        "OPENJSON": lambda self: self._parse_open_json(),
 858        "POSITION": lambda self: self._parse_position(),
 859        "PREDICT": lambda self: self._parse_predict(),
 860        "SAFE_CAST": lambda self: self._parse_cast(False, safe=True),
 861        "STRING_AGG": lambda self: self._parse_string_agg(),
 862        "SUBSTRING": lambda self: self._parse_substring(),
 863        "TRIM": lambda self: self._parse_trim(),
 864        "TRY_CAST": lambda self: self._parse_cast(False, safe=True),
 865        "TRY_CONVERT": lambda self: self._parse_convert(False, safe=True),
 866    }
 867
 868    QUERY_MODIFIER_PARSERS = {
 869        TokenType.MATCH_RECOGNIZE: lambda self: ("match", self._parse_match_recognize()),
 870        TokenType.WHERE: lambda self: ("where", self._parse_where()),
 871        TokenType.GROUP_BY: lambda self: ("group", self._parse_group()),
 872        TokenType.HAVING: lambda self: ("having", self._parse_having()),
 873        TokenType.QUALIFY: lambda self: ("qualify", self._parse_qualify()),
 874        TokenType.WINDOW: lambda self: ("windows", self._parse_window_clause()),
 875        TokenType.ORDER_BY: lambda self: ("order", self._parse_order()),
 876        TokenType.LIMIT: lambda self: ("limit", self._parse_limit()),
 877        TokenType.FETCH: lambda self: ("limit", self._parse_limit()),
 878        TokenType.OFFSET: lambda self: ("offset", self._parse_offset()),
 879        TokenType.FOR: lambda self: ("locks", self._parse_locks()),
 880        TokenType.LOCK: lambda self: ("locks", self._parse_locks()),
 881        TokenType.TABLE_SAMPLE: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
 882        TokenType.USING: lambda self: ("sample", self._parse_table_sample(as_modifier=True)),
 883        TokenType.CLUSTER_BY: lambda self: (
 884            "cluster",
 885            self._parse_sort(exp.Cluster, TokenType.CLUSTER_BY),
 886        ),
 887        TokenType.DISTRIBUTE_BY: lambda self: (
 888            "distribute",
 889            self._parse_sort(exp.Distribute, TokenType.DISTRIBUTE_BY),
 890        ),
 891        TokenType.SORT_BY: lambda self: ("sort", self._parse_sort(exp.Sort, TokenType.SORT_BY)),
 892        TokenType.CONNECT_BY: lambda self: ("connect", self._parse_connect(skip_start_token=True)),
 893        TokenType.START_WITH: lambda self: ("connect", self._parse_connect()),
 894    }
 895
 896    SET_PARSERS = {
 897        "GLOBAL": lambda self: self._parse_set_item_assignment("GLOBAL"),
 898        "LOCAL": lambda self: self._parse_set_item_assignment("LOCAL"),
 899        "SESSION": lambda self: self._parse_set_item_assignment("SESSION"),
 900        "TRANSACTION": lambda self: self._parse_set_transaction(),
 901    }
 902
 903    SHOW_PARSERS: t.Dict[str, t.Callable] = {}
 904
 905    TYPE_LITERAL_PARSERS = {
 906        exp.DataType.Type.JSON: lambda self, this, _: self.expression(exp.ParseJSON, this=this),
 907    }
 908
 909    MODIFIABLES = (exp.Subquery, exp.Subqueryable, exp.Table)
 910
 911    DDL_SELECT_TOKENS = {TokenType.SELECT, TokenType.WITH, TokenType.L_PAREN}
 912
 913    PRE_VOLATILE_TOKENS = {TokenType.CREATE, TokenType.REPLACE, TokenType.UNIQUE}
 914
 915    TRANSACTION_KIND = {"DEFERRED", "IMMEDIATE", "EXCLUSIVE"}
 916    TRANSACTION_CHARACTERISTICS = {
 917        "ISOLATION LEVEL REPEATABLE READ",
 918        "ISOLATION LEVEL READ COMMITTED",
 919        "ISOLATION LEVEL READ UNCOMMITTED",
 920        "ISOLATION LEVEL SERIALIZABLE",
 921        "READ WRITE",
 922        "READ ONLY",
 923    }
 924
 925    INSERT_ALTERNATIVES = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"}
 926
 927    CLONE_KEYWORDS = {"CLONE", "COPY"}
 928    HISTORICAL_DATA_KIND = {"TIMESTAMP", "OFFSET", "STATEMENT", "STREAM"}
 929
 930    OPCLASS_FOLLOW_KEYWORDS = {"ASC", "DESC", "NULLS"}
 931    OPTYPE_FOLLOW_TOKENS = {TokenType.COMMA, TokenType.R_PAREN}
 932
 933    TABLE_INDEX_HINT_TOKENS = {TokenType.FORCE, TokenType.IGNORE, TokenType.USE}
 934
 935    WINDOW_ALIAS_TOKENS = ID_VAR_TOKENS - {TokenType.ROWS}
 936    WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER}
 937    WINDOW_SIDES = {"FOLLOWING", "PRECEDING"}
 938
 939    JSON_KEY_VALUE_SEPARATOR_TOKENS = {TokenType.COLON, TokenType.COMMA, TokenType.IS}
 940
 941    FETCH_TOKENS = ID_VAR_TOKENS - {TokenType.ROW, TokenType.ROWS, TokenType.PERCENT}
 942
 943    ADD_CONSTRAINT_TOKENS = {TokenType.CONSTRAINT, TokenType.PRIMARY_KEY, TokenType.FOREIGN_KEY}
 944
 945    DISTINCT_TOKENS = {TokenType.DISTINCT}
 946
 947    NULL_TOKENS = {TokenType.NULL}
 948
 949    UNNEST_OFFSET_ALIAS_TOKENS = ID_VAR_TOKENS - SET_OPERATIONS
 950
 951    STRICT_CAST = True
 952
 953    PREFIXED_PIVOT_COLUMNS = False
 954    IDENTIFY_PIVOT_STRINGS = False
 955
 956    LOG_DEFAULTS_TO_LN = False
 957
 958    # Whether or not ADD is present for each column added by ALTER TABLE
 959    ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True
 960
 961    # Whether or not the table sample clause expects CSV syntax
 962    TABLESAMPLE_CSV = False
 963
 964    # Whether or not the SET command needs a delimiter (e.g. "=") for assignments
 965    SET_REQUIRES_ASSIGNMENT_DELIMITER = True
 966
 967    # Whether the TRIM function expects the characters to trim as its first argument
 968    TRIM_PATTERN_FIRST = False
 969
 970    # Whether or not string aliases are supported `SELECT COUNT(*) 'count'`
 971    STRING_ALIASES = False
 972
 973    # Whether query modifiers such as LIMIT are attached to the UNION node (vs its right operand)
 974    MODIFIERS_ATTACHED_TO_UNION = True
 975    UNION_MODIFIERS = {"order", "limit", "offset"}
 976
 977    __slots__ = (
 978        "error_level",
 979        "error_message_context",
 980        "max_errors",
 981        "dialect",
 982        "sql",
 983        "errors",
 984        "_tokens",
 985        "_index",
 986        "_curr",
 987        "_next",
 988        "_prev",
 989        "_prev_comments",
 990    )
 991
 992    # Autofilled
 993    SHOW_TRIE: t.Dict = {}
 994    SET_TRIE: t.Dict = {}
 995
 996    def __init__(
 997        self,
 998        error_level: t.Optional[ErrorLevel] = None,
 999        error_message_context: int = 100,
1000        max_errors: int = 3,
1001        dialect: DialectType = None,
1002    ):
1003        from sqlglot.dialects import Dialect
1004
1005        self.error_level = error_level or ErrorLevel.IMMEDIATE
1006        self.error_message_context = error_message_context
1007        self.max_errors = max_errors
1008        self.dialect = Dialect.get_or_raise(dialect)
1009        self.reset()
1010
1011    def reset(self):
1012        self.sql = ""
1013        self.errors = []
1014        self._tokens = []
1015        self._index = 0
1016        self._curr = None
1017        self._next = None
1018        self._prev = None
1019        self._prev_comments = None
1020
1021    def parse(
1022        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1023    ) -> t.List[t.Optional[exp.Expression]]:
1024        """
1025        Parses a list of tokens and returns a list of syntax trees, one tree
1026        per parsed SQL statement.
1027
1028        Args:
1029            raw_tokens: The list of tokens.
1030            sql: The original SQL string, used to produce helpful debug messages.
1031
1032        Returns:
1033            The list of the produced syntax trees.
1034        """
1035        return self._parse(
1036            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1037        )
1038
1039    def parse_into(
1040        self,
1041        expression_types: exp.IntoType,
1042        raw_tokens: t.List[Token],
1043        sql: t.Optional[str] = None,
1044    ) -> t.List[t.Optional[exp.Expression]]:
1045        """
1046        Parses a list of tokens into a given Expression type. If a collection of Expression
1047        types is given instead, this method will try to parse the token list into each one
1048        of them, stopping at the first for which the parsing succeeds.
1049
1050        Args:
1051            expression_types: The expression type(s) to try and parse the token list into.
1052            raw_tokens: The list of tokens.
1053            sql: The original SQL string, used to produce helpful debug messages.
1054
1055        Returns:
1056            The target Expression.
1057        """
1058        errors = []
1059        for expression_type in ensure_list(expression_types):
1060            parser = self.EXPRESSION_PARSERS.get(expression_type)
1061            if not parser:
1062                raise TypeError(f"No parser registered for {expression_type}")
1063
1064            try:
1065                return self._parse(parser, raw_tokens, sql)
1066            except ParseError as e:
1067                e.errors[0]["into_expression"] = expression_type
1068                errors.append(e)
1069
1070        raise ParseError(
1071            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1072            errors=merge_errors(errors),
1073        ) from errors[-1]
1074
1075    def _parse(
1076        self,
1077        parse_method: t.Callable[[Parser], t.Optional[exp.Expression]],
1078        raw_tokens: t.List[Token],
1079        sql: t.Optional[str] = None,
1080    ) -> t.List[t.Optional[exp.Expression]]:
1081        self.reset()
1082        self.sql = sql or ""
1083
1084        total = len(raw_tokens)
1085        chunks: t.List[t.List[Token]] = [[]]
1086
1087        for i, token in enumerate(raw_tokens):
1088            if token.token_type == TokenType.SEMICOLON:
1089                if i < total - 1:
1090                    chunks.append([])
1091            else:
1092                chunks[-1].append(token)
1093
1094        expressions = []
1095
1096        for tokens in chunks:
1097            self._index = -1
1098            self._tokens = tokens
1099            self._advance()
1100
1101            expressions.append(parse_method(self))
1102
1103            if self._index < len(self._tokens):
1104                self.raise_error("Invalid expression / Unexpected token")
1105
1106            self.check_errors()
1107
1108        return expressions
1109
1110    def check_errors(self) -> None:
1111        """Logs or raises any found errors, depending on the chosen error level setting."""
1112        if self.error_level == ErrorLevel.WARN:
1113            for error in self.errors:
1114                logger.error(str(error))
1115        elif self.error_level == ErrorLevel.RAISE and self.errors:
1116            raise ParseError(
1117                concat_messages(self.errors, self.max_errors),
1118                errors=merge_errors(self.errors),
1119            )
1120
1121    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1122        """
1123        Appends an error in the list of recorded errors or raises it, depending on the chosen
1124        error level setting.
1125        """
1126        token = token or self._curr or self._prev or Token.string("")
1127        start = token.start
1128        end = token.end + 1
1129        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1130        highlight = self.sql[start:end]
1131        end_context = self.sql[end : end + self.error_message_context]
1132
1133        error = ParseError.new(
1134            f"{message}. Line {token.line}, Col: {token.col}.\n"
1135            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1136            description=message,
1137            line=token.line,
1138            col=token.col,
1139            start_context=start_context,
1140            highlight=highlight,
1141            end_context=end_context,
1142        )
1143
1144        if self.error_level == ErrorLevel.IMMEDIATE:
1145            raise error
1146
1147        self.errors.append(error)
1148
1149    def expression(
1150        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1151    ) -> E:
1152        """
1153        Creates a new, validated Expression.
1154
1155        Args:
1156            exp_class: The expression class to instantiate.
1157            comments: An optional list of comments to attach to the expression.
1158            kwargs: The arguments to set for the expression along with their respective values.
1159
1160        Returns:
1161            The target expression.
1162        """
1163        instance = exp_class(**kwargs)
1164        instance.add_comments(comments) if comments else self._add_comments(instance)
1165        return self.validate_expression(instance)
1166
1167    def _add_comments(self, expression: t.Optional[exp.Expression]) -> None:
1168        if expression and self._prev_comments:
1169            expression.add_comments(self._prev_comments)
1170            self._prev_comments = None
1171
1172    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1173        """
1174        Validates an Expression, making sure that all its mandatory arguments are set.
1175
1176        Args:
1177            expression: The expression to validate.
1178            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1179
1180        Returns:
1181            The validated expression.
1182        """
1183        if self.error_level != ErrorLevel.IGNORE:
1184            for error_message in expression.error_messages(args):
1185                self.raise_error(error_message)
1186
1187        return expression
1188
1189    def _find_sql(self, start: Token, end: Token) -> str:
1190        return self.sql[start.start : end.end + 1]
1191
1192    def _is_connected(self) -> bool:
1193        return self._prev and self._curr and self._prev.end + 1 == self._curr.start
1194
1195    def _advance(self, times: int = 1) -> None:
1196        self._index += times
1197        self._curr = seq_get(self._tokens, self._index)
1198        self._next = seq_get(self._tokens, self._index + 1)
1199
1200        if self._index > 0:
1201            self._prev = self._tokens[self._index - 1]
1202            self._prev_comments = self._prev.comments
1203        else:
1204            self._prev = None
1205            self._prev_comments = None
1206
1207    def _retreat(self, index: int) -> None:
1208        if index != self._index:
1209            self._advance(index - self._index)
1210
1211    def _parse_command(self) -> exp.Command:
1212        return self.expression(
1213            exp.Command, this=self._prev.text.upper(), expression=self._parse_string()
1214        )
1215
1216    def _parse_comment(self, allow_exists: bool = True) -> exp.Expression:
1217        start = self._prev
1218        exists = self._parse_exists() if allow_exists else None
1219
1220        self._match(TokenType.ON)
1221
1222        kind = self._match_set(self.CREATABLES) and self._prev
1223        if not kind:
1224            return self._parse_as_command(start)
1225
1226        if kind.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1227            this = self._parse_user_defined_function(kind=kind.token_type)
1228        elif kind.token_type == TokenType.TABLE:
1229            this = self._parse_table(alias_tokens=self.COMMENT_TABLE_ALIAS_TOKENS)
1230        elif kind.token_type == TokenType.COLUMN:
1231            this = self._parse_column()
1232        else:
1233            this = self._parse_id_var()
1234
1235        self._match(TokenType.IS)
1236
1237        return self.expression(
1238            exp.Comment, this=this, kind=kind.text, expression=self._parse_string(), exists=exists
1239        )
1240
1241    def _parse_to_table(
1242        self,
1243    ) -> exp.ToTableProperty:
1244        table = self._parse_table_parts(schema=True)
1245        return self.expression(exp.ToTableProperty, this=table)
1246
1247    # https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#mergetree-table-ttl
1248    def _parse_ttl(self) -> exp.Expression:
1249        def _parse_ttl_action() -> t.Optional[exp.Expression]:
1250            this = self._parse_bitwise()
1251
1252            if self._match_text_seq("DELETE"):
1253                return self.expression(exp.MergeTreeTTLAction, this=this, delete=True)
1254            if self._match_text_seq("RECOMPRESS"):
1255                return self.expression(
1256                    exp.MergeTreeTTLAction, this=this, recompress=self._parse_bitwise()
1257                )
1258            if self._match_text_seq("TO", "DISK"):
1259                return self.expression(
1260                    exp.MergeTreeTTLAction, this=this, to_disk=self._parse_string()
1261                )
1262            if self._match_text_seq("TO", "VOLUME"):
1263                return self.expression(
1264                    exp.MergeTreeTTLAction, this=this, to_volume=self._parse_string()
1265                )
1266
1267            return this
1268
1269        expressions = self._parse_csv(_parse_ttl_action)
1270        where = self._parse_where()
1271        group = self._parse_group()
1272
1273        aggregates = None
1274        if group and self._match(TokenType.SET):
1275            aggregates = self._parse_csv(self._parse_set_item)
1276
1277        return self.expression(
1278            exp.MergeTreeTTL,
1279            expressions=expressions,
1280            where=where,
1281            group=group,
1282            aggregates=aggregates,
1283        )
1284
1285    def _parse_statement(self) -> t.Optional[exp.Expression]:
1286        if self._curr is None:
1287            return None
1288
1289        if self._match_set(self.STATEMENT_PARSERS):
1290            return self.STATEMENT_PARSERS[self._prev.token_type](self)
1291
1292        if self._match_set(Tokenizer.COMMANDS):
1293            return self._parse_command()
1294
1295        expression = self._parse_expression()
1296        expression = self._parse_set_operations(expression) if expression else self._parse_select()
1297        return self._parse_query_modifiers(expression)
1298
1299    def _parse_drop(self, exists: bool = False) -> exp.Drop | exp.Command:
1300        start = self._prev
1301        temporary = self._match(TokenType.TEMPORARY)
1302        materialized = self._match_text_seq("MATERIALIZED")
1303
1304        kind = self._match_set(self.CREATABLES) and self._prev.text
1305        if not kind:
1306            return self._parse_as_command(start)
1307
1308        return self.expression(
1309            exp.Drop,
1310            comments=start.comments,
1311            exists=exists or self._parse_exists(),
1312            this=self._parse_table(schema=True),
1313            kind=kind,
1314            temporary=temporary,
1315            materialized=materialized,
1316            cascade=self._match_text_seq("CASCADE"),
1317            constraints=self._match_text_seq("CONSTRAINTS"),
1318            purge=self._match_text_seq("PURGE"),
1319        )
1320
1321    def _parse_exists(self, not_: bool = False) -> t.Optional[bool]:
1322        return (
1323            self._match_text_seq("IF")
1324            and (not not_ or self._match(TokenType.NOT))
1325            and self._match(TokenType.EXISTS)
1326        )
1327
1328    def _parse_create(self) -> exp.Create | exp.Command:
1329        # Note: this can't be None because we've matched a statement parser
1330        start = self._prev
1331        comments = self._prev_comments
1332
1333        replace = start.text.upper() == "REPLACE" or self._match_pair(
1334            TokenType.OR, TokenType.REPLACE
1335        )
1336        unique = self._match(TokenType.UNIQUE)
1337
1338        if self._match_pair(TokenType.TABLE, TokenType.FUNCTION, advance=False):
1339            self._advance()
1340
1341        properties = None
1342        create_token = self._match_set(self.CREATABLES) and self._prev
1343
1344        if not create_token:
1345            # exp.Properties.Location.POST_CREATE
1346            properties = self._parse_properties()
1347            create_token = self._match_set(self.CREATABLES) and self._prev
1348
1349            if not properties or not create_token:
1350                return self._parse_as_command(start)
1351
1352        exists = self._parse_exists(not_=True)
1353        this = None
1354        expression: t.Optional[exp.Expression] = None
1355        indexes = None
1356        no_schema_binding = None
1357        begin = None
1358        end = None
1359        clone = None
1360
1361        def extend_props(temp_props: t.Optional[exp.Properties]) -> None:
1362            nonlocal properties
1363            if properties and temp_props:
1364                properties.expressions.extend(temp_props.expressions)
1365            elif temp_props:
1366                properties = temp_props
1367
1368        if create_token.token_type in (TokenType.FUNCTION, TokenType.PROCEDURE):
1369            this = self._parse_user_defined_function(kind=create_token.token_type)
1370
1371            # exp.Properties.Location.POST_SCHEMA ("schema" here is the UDF's type signature)
1372            extend_props(self._parse_properties())
1373
1374            expression = self._match(TokenType.ALIAS) and self._parse_heredoc()
1375
1376            if not expression:
1377                if self._match(TokenType.COMMAND):
1378                    expression = self._parse_as_command(self._prev)
1379                else:
1380                    begin = self._match(TokenType.BEGIN)
1381                    return_ = self._match_text_seq("RETURN")
1382
1383                    if self._match(TokenType.STRING, advance=False):
1384                        # Takes care of BigQuery's JavaScript UDF definitions that end in an OPTIONS property
1385                        # # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#create_function_statement
1386                        expression = self._parse_string()
1387                        extend_props(self._parse_properties())
1388                    else:
1389                        expression = self._parse_statement()
1390
1391                    end = self._match_text_seq("END")
1392
1393                    if return_:
1394                        expression = self.expression(exp.Return, this=expression)
1395        elif create_token.token_type == TokenType.INDEX:
1396            this = self._parse_index(index=self._parse_id_var())
1397        elif create_token.token_type in self.DB_CREATABLES:
1398            table_parts = self._parse_table_parts(schema=True)
1399
1400            # exp.Properties.Location.POST_NAME
1401            self._match(TokenType.COMMA)
1402            extend_props(self._parse_properties(before=True))
1403
1404            this = self._parse_schema(this=table_parts)
1405
1406            # exp.Properties.Location.POST_SCHEMA and POST_WITH
1407            extend_props(self._parse_properties())
1408
1409            self._match(TokenType.ALIAS)
1410            if not self._match_set(self.DDL_SELECT_TOKENS, advance=False):
1411                # exp.Properties.Location.POST_ALIAS
1412                extend_props(self._parse_properties())
1413
1414            expression = self._parse_ddl_select()
1415
1416            if create_token.token_type == TokenType.TABLE:
1417                # exp.Properties.Location.POST_EXPRESSION
1418                extend_props(self._parse_properties())
1419
1420                indexes = []
1421                while True:
1422                    index = self._parse_index()
1423
1424                    # exp.Properties.Location.POST_INDEX
1425                    extend_props(self._parse_properties())
1426
1427                    if not index:
1428                        break
1429                    else:
1430                        self._match(TokenType.COMMA)
1431                        indexes.append(index)
1432            elif create_token.token_type == TokenType.VIEW:
1433                if self._match_text_seq("WITH", "NO", "SCHEMA", "BINDING"):
1434                    no_schema_binding = True
1435
1436            shallow = self._match_text_seq("SHALLOW")
1437
1438            if self._match_texts(self.CLONE_KEYWORDS):
1439                copy = self._prev.text.lower() == "copy"
1440                clone = self.expression(
1441                    exp.Clone, this=self._parse_table(schema=True), shallow=shallow, copy=copy
1442                )
1443
1444        return self.expression(
1445            exp.Create,
1446            comments=comments,
1447            this=this,
1448            kind=create_token.text.upper(),
1449            replace=replace,
1450            unique=unique,
1451            expression=expression,
1452            exists=exists,
1453            properties=properties,
1454            indexes=indexes,
1455            no_schema_binding=no_schema_binding,
1456            begin=begin,
1457            end=end,
1458            clone=clone,
1459        )
1460
1461    def _parse_property_before(self) -> t.Optional[exp.Expression]:
1462        # only used for teradata currently
1463        self._match(TokenType.COMMA)
1464
1465        kwargs = {
1466            "no": self._match_text_seq("NO"),
1467            "dual": self._match_text_seq("DUAL"),
1468            "before": self._match_text_seq("BEFORE"),
1469            "default": self._match_text_seq("DEFAULT"),
1470            "local": (self._match_text_seq("LOCAL") and "LOCAL")
1471            or (self._match_text_seq("NOT", "LOCAL") and "NOT LOCAL"),
1472            "after": self._match_text_seq("AFTER"),
1473            "minimum": self._match_texts(("MIN", "MINIMUM")),
1474            "maximum": self._match_texts(("MAX", "MAXIMUM")),
1475        }
1476
1477        if self._match_texts(self.PROPERTY_PARSERS):
1478            parser = self.PROPERTY_PARSERS[self._prev.text.upper()]
1479            try:
1480                return parser(self, **{k: v for k, v in kwargs.items() if v})
1481            except TypeError:
1482                self.raise_error(f"Cannot parse property '{self._prev.text}'")
1483
1484        return None
1485
1486    def _parse_property(self) -> t.Optional[exp.Expression]:
1487        if self._match_texts(self.PROPERTY_PARSERS):
1488            return self.PROPERTY_PARSERS[self._prev.text.upper()](self)
1489
1490        if self._match(TokenType.DEFAULT) and self._match_texts(self.PROPERTY_PARSERS):
1491            return self.PROPERTY_PARSERS[self._prev.text.upper()](self, default=True)
1492
1493        if self._match_text_seq("COMPOUND", "SORTKEY"):
1494            return self._parse_sortkey(compound=True)
1495
1496        if self._match_text_seq("SQL", "SECURITY"):
1497            return self.expression(exp.SqlSecurityProperty, definer=self._match_text_seq("DEFINER"))
1498
1499        index = self._index
1500        key = self._parse_column()
1501
1502        if not self._match(TokenType.EQ):
1503            self._retreat(index)
1504            return None
1505
1506        return self.expression(
1507            exp.Property,
1508            this=key.to_dot() if isinstance(key, exp.Column) else key,
1509            value=self._parse_column() or self._parse_var(any_token=True),
1510        )
1511
1512    def _parse_stored(self) -> exp.FileFormatProperty:
1513        self._match(TokenType.ALIAS)
1514
1515        input_format = self._parse_string() if self._match_text_seq("INPUTFORMAT") else None
1516        output_format = self._parse_string() if self._match_text_seq("OUTPUTFORMAT") else None
1517
1518        return self.expression(
1519            exp.FileFormatProperty,
1520            this=self.expression(
1521                exp.InputOutputFormat, input_format=input_format, output_format=output_format
1522            )
1523            if input_format or output_format
1524            else self._parse_var_or_string() or self._parse_number() or self._parse_id_var(),
1525        )
1526
1527    def _parse_property_assignment(self, exp_class: t.Type[E], **kwargs: t.Any) -> E:
1528        self._match(TokenType.EQ)
1529        self._match(TokenType.ALIAS)
1530        return self.expression(exp_class, this=self._parse_field(), **kwargs)
1531
1532    def _parse_properties(self, before: t.Optional[bool] = None) -> t.Optional[exp.Properties]:
1533        properties = []
1534        while True:
1535            if before:
1536                prop = self._parse_property_before()
1537            else:
1538                prop = self._parse_property()
1539
1540            if not prop:
1541                break
1542            for p in ensure_list(prop):
1543                properties.append(p)
1544
1545        if properties:
1546            return self.expression(exp.Properties, expressions=properties)
1547
1548        return None
1549
1550    def _parse_fallback(self, no: bool = False) -> exp.FallbackProperty:
1551        return self.expression(
1552            exp.FallbackProperty, no=no, protection=self._match_text_seq("PROTECTION")
1553        )
1554
1555    def _parse_volatile_property(self) -> exp.VolatileProperty | exp.StabilityProperty:
1556        if self._index >= 2:
1557            pre_volatile_token = self._tokens[self._index - 2]
1558        else:
1559            pre_volatile_token = None
1560
1561        if pre_volatile_token and pre_volatile_token.token_type in self.PRE_VOLATILE_TOKENS:
1562            return exp.VolatileProperty()
1563
1564        return self.expression(exp.StabilityProperty, this=exp.Literal.string("VOLATILE"))
1565
1566    def _parse_system_versioning_property(self) -> exp.WithSystemVersioningProperty:
1567        self._match_pair(TokenType.EQ, TokenType.ON)
1568
1569        prop = self.expression(exp.WithSystemVersioningProperty)
1570        if self._match(TokenType.L_PAREN):
1571            self._match_text_seq("HISTORY_TABLE", "=")
1572            prop.set("this", self._parse_table_parts())
1573
1574            if self._match(TokenType.COMMA):
1575                self._match_text_seq("DATA_CONSISTENCY_CHECK", "=")
1576                prop.set("expression", self._advance_any() and self._prev.text.upper())
1577
1578            self._match_r_paren()
1579
1580        return prop
1581
1582    def _parse_with_property(
1583        self,
1584    ) -> t.Optional[exp.Expression] | t.List[exp.Expression]:
1585        if self._match(TokenType.L_PAREN, advance=False):
1586            return self._parse_wrapped_csv(self._parse_property)
1587
1588        if self._match_text_seq("JOURNAL"):
1589            return self._parse_withjournaltable()
1590
1591        if self._match_text_seq("DATA"):
1592            return self._parse_withdata(no=False)
1593        elif self._match_text_seq("NO", "DATA"):
1594            return self._parse_withdata(no=True)
1595
1596        if not self._next:
1597            return None
1598
1599        return self._parse_withisolatedloading()
1600
1601    # https://dev.mysql.com/doc/refman/8.0/en/create-view.html
1602    def _parse_definer(self) -> t.Optional[exp.DefinerProperty]:
1603        self._match(TokenType.EQ)
1604
1605        user = self._parse_id_var()
1606        self._match(TokenType.PARAMETER)
1607        host = self._parse_id_var() or (self._match(TokenType.MOD) and self._prev.text)
1608
1609        if not user or not host:
1610            return None
1611
1612        return exp.DefinerProperty(this=f"{user}@{host}")
1613
1614    def _parse_withjournaltable(self) -> exp.WithJournalTableProperty:
1615        self._match(TokenType.TABLE)
1616        self._match(TokenType.EQ)
1617        return self.expression(exp.WithJournalTableProperty, this=self._parse_table_parts())
1618
1619    def _parse_log(self, no: bool = False) -> exp.LogProperty:
1620        return self.expression(exp.LogProperty, no=no)
1621
1622    def _parse_journal(self, **kwargs) -> exp.JournalProperty:
1623        return self.expression(exp.JournalProperty, **kwargs)
1624
1625    def _parse_checksum(self) -> exp.ChecksumProperty:
1626        self._match(TokenType.EQ)
1627
1628        on = None
1629        if self._match(TokenType.ON):
1630            on = True
1631        elif self._match_text_seq("OFF"):
1632            on = False
1633
1634        return self.expression(exp.ChecksumProperty, on=on, default=self._match(TokenType.DEFAULT))
1635
1636    def _parse_cluster(self) -> exp.Cluster:
1637        return self.expression(exp.Cluster, expressions=self._parse_csv(self._parse_ordered))
1638
1639    def _parse_clustered_by(self) -> exp.ClusteredByProperty:
1640        self._match_text_seq("BY")
1641
1642        self._match_l_paren()
1643        expressions = self._parse_csv(self._parse_column)
1644        self._match_r_paren()
1645
1646        if self._match_text_seq("SORTED", "BY"):
1647            self._match_l_paren()
1648            sorted_by = self._parse_csv(self._parse_ordered)
1649            self._match_r_paren()
1650        else:
1651            sorted_by = None
1652
1653        self._match(TokenType.INTO)
1654        buckets = self._parse_number()
1655        self._match_text_seq("BUCKETS")
1656
1657        return self.expression(
1658            exp.ClusteredByProperty,
1659            expressions=expressions,
1660            sorted_by=sorted_by,
1661            buckets=buckets,
1662        )
1663
1664    def _parse_copy_property(self) -> t.Optional[exp.CopyGrantsProperty]:
1665        if not self._match_text_seq("GRANTS"):
1666            self._retreat(self._index - 1)
1667            return None
1668
1669        return self.expression(exp.CopyGrantsProperty)
1670
1671    def _parse_freespace(self) -> exp.FreespaceProperty:
1672        self._match(TokenType.EQ)
1673        return self.expression(
1674            exp.FreespaceProperty, this=self._parse_number(), percent=self._match(TokenType.PERCENT)
1675        )
1676
1677    def _parse_mergeblockratio(
1678        self, no: bool = False, default: bool = False
1679    ) -> exp.MergeBlockRatioProperty:
1680        if self._match(TokenType.EQ):
1681            return self.expression(
1682                exp.MergeBlockRatioProperty,
1683                this=self._parse_number(),
1684                percent=self._match(TokenType.PERCENT),
1685            )
1686
1687        return self.expression(exp.MergeBlockRatioProperty, no=no, default=default)
1688
1689    def _parse_datablocksize(
1690        self,
1691        default: t.Optional[bool] = None,
1692        minimum: t.Optional[bool] = None,
1693        maximum: t.Optional[bool] = None,
1694    ) -> exp.DataBlocksizeProperty:
1695        self._match(TokenType.EQ)
1696        size = self._parse_number()
1697
1698        units = None
1699        if self._match_texts(("BYTES", "KBYTES", "KILOBYTES")):
1700            units = self._prev.text
1701
1702        return self.expression(
1703            exp.DataBlocksizeProperty,
1704            size=size,
1705            units=units,
1706            default=default,
1707            minimum=minimum,
1708            maximum=maximum,
1709        )
1710
1711    def _parse_blockcompression(self) -> exp.BlockCompressionProperty:
1712        self._match(TokenType.EQ)
1713        always = self._match_text_seq("ALWAYS")
1714        manual = self._match_text_seq("MANUAL")
1715        never = self._match_text_seq("NEVER")
1716        default = self._match_text_seq("DEFAULT")
1717
1718        autotemp = None
1719        if self._match_text_seq("AUTOTEMP"):
1720            autotemp = self._parse_schema()
1721
1722        return self.expression(
1723            exp.BlockCompressionProperty,
1724            always=always,
1725            manual=manual,
1726            never=never,
1727            default=default,
1728            autotemp=autotemp,
1729        )
1730
1731    def _parse_withisolatedloading(self) -> exp.IsolatedLoadingProperty:
1732        no = self._match_text_seq("NO")
1733        concurrent = self._match_text_seq("CONCURRENT")
1734        self._match_text_seq("ISOLATED", "LOADING")
1735        for_all = self._match_text_seq("FOR", "ALL")
1736        for_insert = self._match_text_seq("FOR", "INSERT")
1737        for_none = self._match_text_seq("FOR", "NONE")
1738        return self.expression(
1739            exp.IsolatedLoadingProperty,
1740            no=no,
1741            concurrent=concurrent,
1742            for_all=for_all,
1743            for_insert=for_insert,
1744            for_none=for_none,
1745        )
1746
1747    def _parse_locking(self) -> exp.LockingProperty:
1748        if self._match(TokenType.TABLE):
1749            kind = "TABLE"
1750        elif self._match(TokenType.VIEW):
1751            kind = "VIEW"
1752        elif self._match(TokenType.ROW):
1753            kind = "ROW"
1754        elif self._match_text_seq("DATABASE"):
1755            kind = "DATABASE"
1756        else:
1757            kind = None
1758
1759        if kind in ("DATABASE", "TABLE", "VIEW"):
1760            this = self._parse_table_parts()
1761        else:
1762            this = None
1763
1764        if self._match(TokenType.FOR):
1765            for_or_in = "FOR"
1766        elif self._match(TokenType.IN):
1767            for_or_in = "IN"
1768        else:
1769            for_or_in = None
1770
1771        if self._match_text_seq("ACCESS"):
1772            lock_type = "ACCESS"
1773        elif self._match_texts(("EXCL", "EXCLUSIVE")):
1774            lock_type = "EXCLUSIVE"
1775        elif self._match_text_seq("SHARE"):
1776            lock_type = "SHARE"
1777        elif self._match_text_seq("READ"):
1778            lock_type = "READ"
1779        elif self._match_text_seq("WRITE"):
1780            lock_type = "WRITE"
1781        elif self._match_text_seq("CHECKSUM"):
1782            lock_type = "CHECKSUM"
1783        else:
1784            lock_type = None
1785
1786        override = self._match_text_seq("OVERRIDE")
1787
1788        return self.expression(
1789            exp.LockingProperty,
1790            this=this,
1791            kind=kind,
1792            for_or_in=for_or_in,
1793            lock_type=lock_type,
1794            override=override,
1795        )
1796
1797    def _parse_partition_by(self) -> t.List[exp.Expression]:
1798        if self._match(TokenType.PARTITION_BY):
1799            return self._parse_csv(self._parse_conjunction)
1800        return []
1801
1802    def _parse_partition_bound_spec(self) -> exp.PartitionBoundSpec:
1803        def _parse_partition_bound_expr() -> t.Optional[exp.Expression]:
1804            if self._match_text_seq("MINVALUE"):
1805                return exp.var("MINVALUE")
1806            if self._match_text_seq("MAXVALUE"):
1807                return exp.var("MAXVALUE")
1808            return self._parse_bitwise()
1809
1810        this: t.Optional[exp.Expression | t.List[exp.Expression]] = None
1811        expression = None
1812        from_expressions = None
1813        to_expressions = None
1814
1815        if self._match(TokenType.IN):
1816            this = self._parse_wrapped_csv(self._parse_bitwise)
1817        elif self._match(TokenType.FROM):
1818            from_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
1819            self._match_text_seq("TO")
1820            to_expressions = self._parse_wrapped_csv(_parse_partition_bound_expr)
1821        elif self._match_text_seq("WITH", "(", "MODULUS"):
1822            this = self._parse_number()
1823            self._match_text_seq(",", "REMAINDER")
1824            expression = self._parse_number()
1825            self._match_r_paren()
1826        else:
1827            self.raise_error("Failed to parse partition bound spec.")
1828
1829        return self.expression(
1830            exp.PartitionBoundSpec,
1831            this=this,
1832            expression=expression,
1833            from_expressions=from_expressions,
1834            to_expressions=to_expressions,
1835        )
1836
1837    # https://www.postgresql.org/docs/current/sql-createtable.html
1838    def _parse_partitioned_of(self) -> t.Optional[exp.PartitionedOfProperty]:
1839        if not self._match_text_seq("OF"):
1840            self._retreat(self._index - 1)
1841            return None
1842
1843        this = self._parse_table(schema=True)
1844
1845        if self._match(TokenType.DEFAULT):
1846            expression: exp.Var | exp.PartitionBoundSpec = exp.var("DEFAULT")
1847        elif self._match_text_seq("FOR", "VALUES"):
1848            expression = self._parse_partition_bound_spec()
1849        else:
1850            self.raise_error("Expecting either DEFAULT or FOR VALUES clause.")
1851
1852        return self.expression(exp.PartitionedOfProperty, this=this, expression=expression)
1853
1854    def _parse_partitioned_by(self) -> exp.PartitionedByProperty:
1855        self._match(TokenType.EQ)
1856        return self.expression(
1857            exp.PartitionedByProperty,
1858            this=self._parse_schema() or self._parse_bracket(self._parse_field()),
1859        )
1860
1861    def _parse_withdata(self, no: bool = False) -> exp.WithDataProperty:
1862        if self._match_text_seq("AND", "STATISTICS"):
1863            statistics = True
1864        elif self._match_text_seq("AND", "NO", "STATISTICS"):
1865            statistics = False
1866        else:
1867            statistics = None
1868
1869        return self.expression(exp.WithDataProperty, no=no, statistics=statistics)
1870
1871    def _parse_contains_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
1872        if self._match_text_seq("SQL"):
1873            return self.expression(exp.SqlReadWriteProperty, this="CONTAINS SQL")
1874        return None
1875
1876    def _parse_modifies_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
1877        if self._match_text_seq("SQL", "DATA"):
1878            return self.expression(exp.SqlReadWriteProperty, this="MODIFIES SQL DATA")
1879        return None
1880
1881    def _parse_no_property(self) -> t.Optional[exp.Expression]:
1882        if self._match_text_seq("PRIMARY", "INDEX"):
1883            return exp.NoPrimaryIndexProperty()
1884        if self._match_text_seq("SQL"):
1885            return self.expression(exp.SqlReadWriteProperty, this="NO SQL")
1886        return None
1887
1888    def _parse_on_property(self) -> t.Optional[exp.Expression]:
1889        if self._match_text_seq("COMMIT", "PRESERVE", "ROWS"):
1890            return exp.OnCommitProperty()
1891        if self._match_text_seq("COMMIT", "DELETE", "ROWS"):
1892            return exp.OnCommitProperty(delete=True)
1893        return self.expression(exp.OnProperty, this=self._parse_schema(self._parse_id_var()))
1894
1895    def _parse_reads_property(self) -> t.Optional[exp.SqlReadWriteProperty]:
1896        if self._match_text_seq("SQL", "DATA"):
1897            return self.expression(exp.SqlReadWriteProperty, this="READS SQL DATA")
1898        return None
1899
1900    def _parse_distkey(self) -> exp.DistKeyProperty:
1901        return self.expression(exp.DistKeyProperty, this=self._parse_wrapped(self._parse_id_var))
1902
1903    def _parse_create_like(self) -> t.Optional[exp.LikeProperty]:
1904        table = self._parse_table(schema=True)
1905
1906        options = []
1907        while self._match_texts(("INCLUDING", "EXCLUDING")):
1908            this = self._prev.text.upper()
1909
1910            id_var = self._parse_id_var()
1911            if not id_var:
1912                return None
1913
1914            options.append(
1915                self.expression(exp.Property, this=this, value=exp.var(id_var.this.upper()))
1916            )
1917
1918        return self.expression(exp.LikeProperty, this=table, expressions=options)
1919
1920    def _parse_sortkey(self, compound: bool = False) -> exp.SortKeyProperty:
1921        return self.expression(
1922            exp.SortKeyProperty, this=self._parse_wrapped_id_vars(), compound=compound
1923        )
1924
1925    def _parse_character_set(self, default: bool = False) -> exp.CharacterSetProperty:
1926        self._match(TokenType.EQ)
1927        return self.expression(
1928            exp.CharacterSetProperty, this=self._parse_var_or_string(), default=default
1929        )
1930
1931    def _parse_remote_with_connection(self) -> exp.RemoteWithConnectionModelProperty:
1932        self._match_text_seq("WITH", "CONNECTION")
1933        return self.expression(
1934            exp.RemoteWithConnectionModelProperty, this=self._parse_table_parts()
1935        )
1936
1937    def _parse_returns(self) -> exp.ReturnsProperty:
1938        value: t.Optional[exp.Expression]
1939        is_table = self._match(TokenType.TABLE)
1940
1941        if is_table:
1942            if self._match(TokenType.LT):
1943                value = self.expression(
1944                    exp.Schema,
1945                    this="TABLE",
1946                    expressions=self._parse_csv(self._parse_struct_types),
1947                )
1948                if not self._match(TokenType.GT):
1949                    self.raise_error("Expecting >")
1950            else:
1951                value = self._parse_schema(exp.var("TABLE"))
1952        else:
1953            value = self._parse_types()
1954
1955        return self.expression(exp.ReturnsProperty, this=value, is_table=is_table)
1956
1957    def _parse_describe(self) -> exp.Describe:
1958        kind = self._match_set(self.CREATABLES) and self._prev.text
1959        extended = self._match_text_seq("EXTENDED")
1960        this = self._parse_table(schema=True)
1961        properties = self._parse_properties()
1962        expressions = properties.expressions if properties else None
1963        return self.expression(
1964            exp.Describe, this=this, extended=extended, kind=kind, expressions=expressions
1965        )
1966
1967    def _parse_insert(self) -> exp.Insert:
1968        comments = ensure_list(self._prev_comments)
1969        overwrite = self._match(TokenType.OVERWRITE)
1970        ignore = self._match(TokenType.IGNORE)
1971        local = self._match_text_seq("LOCAL")
1972        alternative = None
1973
1974        if self._match_text_seq("DIRECTORY"):
1975            this: t.Optional[exp.Expression] = self.expression(
1976                exp.Directory,
1977                this=self._parse_var_or_string(),
1978                local=local,
1979                row_format=self._parse_row_format(match_row=True),
1980            )
1981        else:
1982            if self._match(TokenType.OR):
1983                alternative = self._match_texts(self.INSERT_ALTERNATIVES) and self._prev.text
1984
1985            self._match(TokenType.INTO)
1986            comments += ensure_list(self._prev_comments)
1987            self._match(TokenType.TABLE)
1988            this = self._parse_table(schema=True)
1989
1990        returning = self._parse_returning()
1991
1992        return self.expression(
1993            exp.Insert,
1994            comments=comments,
1995            this=this,
1996            by_name=self._match_text_seq("BY", "NAME"),
1997            exists=self._parse_exists(),
1998            partition=self._parse_partition(),
1999            where=self._match_pair(TokenType.REPLACE, TokenType.WHERE)
2000            and self._parse_conjunction(),
2001            expression=self._parse_ddl_select(),
2002            conflict=self._parse_on_conflict(),
2003            returning=returning or self._parse_returning(),
2004            overwrite=overwrite,
2005            alternative=alternative,
2006            ignore=ignore,
2007        )
2008
2009    def _parse_kill(self) -> exp.Kill:
2010        kind = exp.var(self._prev.text) if self._match_texts(("CONNECTION", "QUERY")) else None
2011
2012        return self.expression(
2013            exp.Kill,
2014            this=self._parse_primary(),
2015            kind=kind,
2016        )
2017
2018    def _parse_on_conflict(self) -> t.Optional[exp.OnConflict]:
2019        conflict = self._match_text_seq("ON", "CONFLICT")
2020        duplicate = self._match_text_seq("ON", "DUPLICATE", "KEY")
2021
2022        if not conflict and not duplicate:
2023            return None
2024
2025        nothing = None
2026        expressions = None
2027        key = None
2028        constraint = None
2029
2030        if conflict:
2031            if self._match_text_seq("ON", "CONSTRAINT"):
2032                constraint = self._parse_id_var()
2033            else:
2034                key = self._parse_csv(self._parse_value)
2035
2036        self._match_text_seq("DO")
2037        if self._match_text_seq("NOTHING"):
2038            nothing = True
2039        else:
2040            self._match(TokenType.UPDATE)
2041            self._match(TokenType.SET)
2042            expressions = self._parse_csv(self._parse_equality)
2043
2044        return self.expression(
2045            exp.OnConflict,
2046            duplicate=duplicate,
2047            expressions=expressions,
2048            nothing=nothing,
2049            key=key,
2050            constraint=constraint,
2051        )
2052
2053    def _parse_returning(self) -> t.Optional[exp.Returning]:
2054        if not self._match(TokenType.RETURNING):
2055            return None
2056        return self.expression(
2057            exp.Returning,
2058            expressions=self._parse_csv(self._parse_expression),
2059            into=self._match(TokenType.INTO) and self._parse_table_part(),
2060        )
2061
2062    def _parse_row(self) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2063        if not self._match(TokenType.FORMAT):
2064            return None
2065        return self._parse_row_format()
2066
2067    def _parse_row_format(
2068        self, match_row: bool = False
2069    ) -> t.Optional[exp.RowFormatSerdeProperty | exp.RowFormatDelimitedProperty]:
2070        if match_row and not self._match_pair(TokenType.ROW, TokenType.FORMAT):
2071            return None
2072
2073        if self._match_text_seq("SERDE"):
2074            this = self._parse_string()
2075
2076            serde_properties = None
2077            if self._match(TokenType.SERDE_PROPERTIES):
2078                serde_properties = self.expression(
2079                    exp.SerdeProperties, expressions=self._parse_wrapped_csv(self._parse_property)
2080                )
2081
2082            return self.expression(
2083                exp.RowFormatSerdeProperty, this=this, serde_properties=serde_properties
2084            )
2085
2086        self._match_text_seq("DELIMITED")
2087
2088        kwargs = {}
2089
2090        if self._match_text_seq("FIELDS", "TERMINATED", "BY"):
2091            kwargs["fields"] = self._parse_string()
2092            if self._match_text_seq("ESCAPED", "BY"):
2093                kwargs["escaped"] = self._parse_string()
2094        if self._match_text_seq("COLLECTION", "ITEMS", "TERMINATED", "BY"):
2095            kwargs["collection_items"] = self._parse_string()
2096        if self._match_text_seq("MAP", "KEYS", "TERMINATED", "BY"):
2097            kwargs["map_keys"] = self._parse_string()
2098        if self._match_text_seq("LINES", "TERMINATED", "BY"):
2099            kwargs["lines"] = self._parse_string()
2100        if self._match_text_seq("NULL", "DEFINED", "AS"):
2101            kwargs["null"] = self._parse_string()
2102
2103        return self.expression(exp.RowFormatDelimitedProperty, **kwargs)  # type: ignore
2104
2105    def _parse_load(self) -> exp.LoadData | exp.Command:
2106        if self._match_text_seq("DATA"):
2107            local = self._match_text_seq("LOCAL")
2108            self._match_text_seq("INPATH")
2109            inpath = self._parse_string()
2110            overwrite = self._match(TokenType.OVERWRITE)
2111            self._match_pair(TokenType.INTO, TokenType.TABLE)
2112
2113            return self.expression(
2114                exp.LoadData,
2115                this=self._parse_table(schema=True),
2116                local=local,
2117                overwrite=overwrite,
2118                inpath=inpath,
2119                partition=self._parse_partition(),
2120                input_format=self._match_text_seq("INPUTFORMAT") and self._parse_string(),
2121                serde=self._match_text_seq("SERDE") and self._parse_string(),
2122            )
2123        return self._parse_as_command(self._prev)
2124
2125    def _parse_delete(self) -> exp.Delete:
2126        # This handles MySQL's "Multiple-Table Syntax"
2127        # https://dev.mysql.com/doc/refman/8.0/en/delete.html
2128        tables = None
2129        comments = self._prev_comments
2130        if not self._match(TokenType.FROM, advance=False):
2131            tables = self._parse_csv(self._parse_table) or None
2132
2133        returning = self._parse_returning()
2134
2135        return self.expression(
2136            exp.Delete,
2137            comments=comments,
2138            tables=tables,
2139            this=self._match(TokenType.FROM) and self._parse_table(joins=True),
2140            using=self._match(TokenType.USING) and self._parse_table(joins=True),
2141            where=self._parse_where(),
2142            returning=returning or self._parse_returning(),
2143            limit=self._parse_limit(),
2144        )
2145
2146    def _parse_update(self) -> exp.Update:
2147        comments = self._prev_comments
2148        this = self._parse_table(joins=True, alias_tokens=self.UPDATE_ALIAS_TOKENS)
2149        expressions = self._match(TokenType.SET) and self._parse_csv(self._parse_equality)
2150        returning = self._parse_returning()
2151        return self.expression(
2152            exp.Update,
2153            comments=comments,
2154            **{  # type: ignore
2155                "this": this,
2156                "expressions": expressions,
2157                "from": self._parse_from(joins=True),
2158                "where": self._parse_where(),
2159                "returning": returning or self._parse_returning(),
2160                "order": self._parse_order(),
2161                "limit": self._parse_limit(),
2162            },
2163        )
2164
2165    def _parse_uncache(self) -> exp.Uncache:
2166        if not self._match(TokenType.TABLE):
2167            self.raise_error("Expecting TABLE after UNCACHE")
2168
2169        return self.expression(
2170            exp.Uncache, exists=self._parse_exists(), this=self._parse_table(schema=True)
2171        )
2172
2173    def _parse_cache(self) -> exp.Cache:
2174        lazy = self._match_text_seq("LAZY")
2175        self._match(TokenType.TABLE)
2176        table = self._parse_table(schema=True)
2177
2178        options = []
2179        if self._match_text_seq("OPTIONS"):
2180            self._match_l_paren()
2181            k = self._parse_string()
2182            self._match(TokenType.EQ)
2183            v = self._parse_string()
2184            options = [k, v]
2185            self._match_r_paren()
2186
2187        self._match(TokenType.ALIAS)
2188        return self.expression(
2189            exp.Cache,
2190            this=table,
2191            lazy=lazy,
2192            options=options,
2193            expression=self._parse_select(nested=True),
2194        )
2195
2196    def _parse_partition(self) -> t.Optional[exp.Partition]:
2197        if not self._match(TokenType.PARTITION):
2198            return None
2199
2200        return self.expression(
2201            exp.Partition, expressions=self._parse_wrapped_csv(self._parse_conjunction)
2202        )
2203
2204    def _parse_value(self) -> exp.Tuple:
2205        if self._match(TokenType.L_PAREN):
2206            expressions = self._parse_csv(self._parse_expression)
2207            self._match_r_paren()
2208            return self.expression(exp.Tuple, expressions=expressions)
2209
2210        # In presto we can have VALUES 1, 2 which results in 1 column & 2 rows.
2211        # https://prestodb.io/docs/current/sql/values.html
2212        return self.expression(exp.Tuple, expressions=[self._parse_expression()])
2213
2214    def _parse_projections(self) -> t.List[exp.Expression]:
2215        return self._parse_expressions()
2216
2217    def _parse_select(
2218        self,
2219        nested: bool = False,
2220        table: bool = False,
2221        parse_subquery_alias: bool = True,
2222        parse_set_operation: bool = True,
2223    ) -> t.Optional[exp.Expression]:
2224        cte = self._parse_with()
2225
2226        if cte:
2227            this = self._parse_statement()
2228
2229            if not this:
2230                self.raise_error("Failed to parse any statement following CTE")
2231                return cte
2232
2233            if "with" in this.arg_types:
2234                this.set("with", cte)
2235            else:
2236                self.raise_error(f"{this.key} does not support CTE")
2237                this = cte
2238
2239            return this
2240
2241        # duckdb supports leading with FROM x
2242        from_ = self._parse_from() if self._match(TokenType.FROM, advance=False) else None
2243
2244        if self._match(TokenType.SELECT):
2245            comments = self._prev_comments
2246
2247            hint = self._parse_hint()
2248            all_ = self._match(TokenType.ALL)
2249            distinct = self._match_set(self.DISTINCT_TOKENS)
2250
2251            kind = (
2252                self._match(TokenType.ALIAS)
2253                and self._match_texts(("STRUCT", "VALUE"))
2254                and self._prev.text.upper()
2255            )
2256
2257            if distinct:
2258                distinct = self.expression(
2259                    exp.Distinct,
2260                    on=self._parse_value() if self._match(TokenType.ON) else None,
2261                )
2262
2263            if all_ and distinct:
2264                self.raise_error("Cannot specify both ALL and DISTINCT after SELECT")
2265
2266            limit = self._parse_limit(top=True)
2267            projections = self._parse_projections()
2268
2269            this = self.expression(
2270                exp.Select,
2271                kind=kind,
2272                hint=hint,
2273                distinct=distinct,
2274                expressions=projections,
2275                limit=limit,
2276            )
2277            this.comments = comments
2278
2279            into = self._parse_into()
2280            if into:
2281                this.set("into", into)
2282
2283            if not from_:
2284                from_ = self._parse_from()
2285
2286            if from_:
2287                this.set("from", from_)
2288
2289            this = self._parse_query_modifiers(this)
2290        elif (table or nested) and self._match(TokenType.L_PAREN):
2291            if self._match(TokenType.PIVOT):
2292                this = self._parse_simplified_pivot()
2293            elif self._match(TokenType.FROM):
2294                this = exp.select("*").from_(
2295                    t.cast(exp.From, self._parse_from(skip_from_token=True))
2296                )
2297            else:
2298                this = (
2299                    self._parse_table()
2300                    if table
2301                    else self._parse_select(nested=True, parse_set_operation=False)
2302                )
2303                this = self._parse_query_modifiers(self._parse_set_operations(this))
2304
2305            self._match_r_paren()
2306
2307            # We return early here so that the UNION isn't attached to the subquery by the
2308            # following call to _parse_set_operations, but instead becomes the parent node
2309            return self._parse_subquery(this, parse_alias=parse_subquery_alias)
2310        elif self._match(TokenType.VALUES):
2311            this = self.expression(
2312                exp.Values,
2313                expressions=self._parse_csv(self._parse_value),
2314                alias=self._parse_table_alias(),
2315            )
2316        elif from_:
2317            this = exp.select("*").from_(from_.this, copy=False)
2318        else:
2319            this = None
2320
2321        if parse_set_operation:
2322            return self._parse_set_operations(this)
2323        return this
2324
2325    def _parse_with(self, skip_with_token: bool = False) -> t.Optional[exp.With]:
2326        if not skip_with_token and not self._match(TokenType.WITH):
2327            return None
2328
2329        comments = self._prev_comments
2330        recursive = self._match(TokenType.RECURSIVE)
2331
2332        expressions = []
2333        while True:
2334            expressions.append(self._parse_cte())
2335
2336            if not self._match(TokenType.COMMA) and not self._match(TokenType.WITH):
2337                break
2338            else:
2339                self._match(TokenType.WITH)
2340
2341        return self.expression(
2342            exp.With, comments=comments, expressions=expressions, recursive=recursive
2343        )
2344
2345    def _parse_cte(self) -> exp.CTE:
2346        alias = self._parse_table_alias(self.ID_VAR_TOKENS)
2347        if not alias or not alias.this:
2348            self.raise_error("Expected CTE to have alias")
2349
2350        self._match(TokenType.ALIAS)
2351        return self.expression(
2352            exp.CTE, this=self._parse_wrapped(self._parse_statement), alias=alias
2353        )
2354
2355    def _parse_table_alias(
2356        self, alias_tokens: t.Optional[t.Collection[TokenType]] = None
2357    ) -> t.Optional[exp.TableAlias]:
2358        any_token = self._match(TokenType.ALIAS)
2359        alias = (
2360            self._parse_id_var(any_token=any_token, tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
2361            or self._parse_string_as_identifier()
2362        )
2363
2364        index = self._index
2365        if self._match(TokenType.L_PAREN):
2366            columns = self._parse_csv(self._parse_function_parameter)
2367            self._match_r_paren() if columns else self._retreat(index)
2368        else:
2369            columns = None
2370
2371        if not alias and not columns:
2372            return None
2373
2374        return self.expression(exp.TableAlias, this=alias, columns=columns)
2375
2376    def _parse_subquery(
2377        self, this: t.Optional[exp.Expression], parse_alias: bool = True
2378    ) -> t.Optional[exp.Subquery]:
2379        if not this:
2380            return None
2381
2382        return self.expression(
2383            exp.Subquery,
2384            this=this,
2385            pivots=self._parse_pivots(),
2386            alias=self._parse_table_alias() if parse_alias else None,
2387        )
2388
2389    def _parse_query_modifiers(
2390        self, this: t.Optional[exp.Expression]
2391    ) -> t.Optional[exp.Expression]:
2392        if isinstance(this, self.MODIFIABLES):
2393            for join in iter(self._parse_join, None):
2394                this.append("joins", join)
2395            for lateral in iter(self._parse_lateral, None):
2396                this.append("laterals", lateral)
2397
2398            while True:
2399                if self._match_set(self.QUERY_MODIFIER_PARSERS, advance=False):
2400                    parser = self.QUERY_MODIFIER_PARSERS[self._curr.token_type]
2401                    key, expression = parser(self)
2402
2403                    if expression:
2404                        this.set(key, expression)
2405                        if key == "limit":
2406                            offset = expression.args.pop("offset", None)
2407                            if offset:
2408                                this.set("offset", exp.Offset(expression=offset))
2409                        continue
2410                break
2411        return this
2412
2413    def _parse_hint(self) -> t.Optional[exp.Hint]:
2414        if self._match(TokenType.HINT):
2415            hints = []
2416            for hint in iter(lambda: self._parse_csv(self._parse_function), []):
2417                hints.extend(hint)
2418
2419            if not self._match_pair(TokenType.STAR, TokenType.SLASH):
2420                self.raise_error("Expected */ after HINT")
2421
2422            return self.expression(exp.Hint, expressions=hints)
2423
2424        return None
2425
2426    def _parse_into(self) -> t.Optional[exp.Into]:
2427        if not self._match(TokenType.INTO):
2428            return None
2429
2430        temp = self._match(TokenType.TEMPORARY)
2431        unlogged = self._match_text_seq("UNLOGGED")
2432        self._match(TokenType.TABLE)
2433
2434        return self.expression(
2435            exp.Into, this=self._parse_table(schema=True), temporary=temp, unlogged=unlogged
2436        )
2437
2438    def _parse_from(
2439        self, joins: bool = False, skip_from_token: bool = False
2440    ) -> t.Optional[exp.From]:
2441        if not skip_from_token and not self._match(TokenType.FROM):
2442            return None
2443
2444        return self.expression(
2445            exp.From, comments=self._prev_comments, this=self._parse_table(joins=joins)
2446        )
2447
2448    def _parse_match_recognize(self) -> t.Optional[exp.MatchRecognize]:
2449        if not self._match(TokenType.MATCH_RECOGNIZE):
2450            return None
2451
2452        self._match_l_paren()
2453
2454        partition = self._parse_partition_by()
2455        order = self._parse_order()
2456        measures = self._parse_expressions() if self._match_text_seq("MEASURES") else None
2457
2458        if self._match_text_seq("ONE", "ROW", "PER", "MATCH"):
2459            rows = exp.var("ONE ROW PER MATCH")
2460        elif self._match_text_seq("ALL", "ROWS", "PER", "MATCH"):
2461            text = "ALL ROWS PER MATCH"
2462            if self._match_text_seq("SHOW", "EMPTY", "MATCHES"):
2463                text += f" SHOW EMPTY MATCHES"
2464            elif self._match_text_seq("OMIT", "EMPTY", "MATCHES"):
2465                text += f" OMIT EMPTY MATCHES"
2466            elif self._match_text_seq("WITH", "UNMATCHED", "ROWS"):
2467                text += f" WITH UNMATCHED ROWS"
2468            rows = exp.var(text)
2469        else:
2470            rows = None
2471
2472        if self._match_text_seq("AFTER", "MATCH", "SKIP"):
2473            text = "AFTER MATCH SKIP"
2474            if self._match_text_seq("PAST", "LAST", "ROW"):
2475                text += f" PAST LAST ROW"
2476            elif self._match_text_seq("TO", "NEXT", "ROW"):
2477                text += f" TO NEXT ROW"
2478            elif self._match_text_seq("TO", "FIRST"):
2479                text += f" TO FIRST {self._advance_any().text}"  # type: ignore
2480            elif self._match_text_seq("TO", "LAST"):
2481                text += f" TO LAST {self._advance_any().text}"  # type: ignore
2482            after = exp.var(text)
2483        else:
2484            after = None
2485
2486        if self._match_text_seq("PATTERN"):
2487            self._match_l_paren()
2488
2489            if not self._curr:
2490                self.raise_error("Expecting )", self._curr)
2491
2492            paren = 1
2493            start = self._curr
2494
2495            while self._curr and paren > 0:
2496                if self._curr.token_type == TokenType.L_PAREN:
2497                    paren += 1
2498                if self._curr.token_type == TokenType.R_PAREN:
2499                    paren -= 1
2500
2501                end = self._prev
2502                self._advance()
2503
2504            if paren > 0:
2505                self.raise_error("Expecting )", self._curr)
2506
2507            pattern = exp.var(self._find_sql(start, end))
2508        else:
2509            pattern = None
2510
2511        define = (
2512            self._parse_csv(self._parse_name_as_expression)
2513            if self._match_text_seq("DEFINE")
2514            else None
2515        )
2516
2517        self._match_r_paren()
2518
2519        return self.expression(
2520            exp.MatchRecognize,
2521            partition_by=partition,
2522            order=order,
2523            measures=measures,
2524            rows=rows,
2525            after=after,
2526            pattern=pattern,
2527            define=define,
2528            alias=self._parse_table_alias(),
2529        )
2530
2531    def _parse_lateral(self) -> t.Optional[exp.Lateral]:
2532        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY)
2533        if not cross_apply and self._match_pair(TokenType.OUTER, TokenType.APPLY):
2534            cross_apply = False
2535
2536        if cross_apply is not None:
2537            this = self._parse_select(table=True)
2538            view = None
2539            outer = None
2540        elif self._match(TokenType.LATERAL):
2541            this = self._parse_select(table=True)
2542            view = self._match(TokenType.VIEW)
2543            outer = self._match(TokenType.OUTER)
2544        else:
2545            return None
2546
2547        if not this:
2548            this = (
2549                self._parse_unnest()
2550                or self._parse_function()
2551                or self._parse_id_var(any_token=False)
2552            )
2553
2554            while self._match(TokenType.DOT):
2555                this = exp.Dot(
2556                    this=this,
2557                    expression=self._parse_function() or self._parse_id_var(any_token=False),
2558                )
2559
2560        if view:
2561            table = self._parse_id_var(any_token=False)
2562            columns = self._parse_csv(self._parse_id_var) if self._match(TokenType.ALIAS) else []
2563            table_alias: t.Optional[exp.TableAlias] = self.expression(
2564                exp.TableAlias, this=table, columns=columns
2565            )
2566        elif isinstance(this, (exp.Subquery, exp.Unnest)) and this.alias:
2567            # We move the alias from the lateral's child node to the lateral itself
2568            table_alias = this.args["alias"].pop()
2569        else:
2570            table_alias = self._parse_table_alias()
2571
2572        return self.expression(
2573            exp.Lateral,
2574            this=this,
2575            view=view,
2576            outer=outer,
2577            alias=table_alias,
2578            cross_apply=cross_apply,
2579        )
2580
2581    def _parse_join_parts(
2582        self,
2583    ) -> t.Tuple[t.Optional[Token], t.Optional[Token], t.Optional[Token]]:
2584        return (
2585            self._match_set(self.JOIN_METHODS) and self._prev,
2586            self._match_set(self.JOIN_SIDES) and self._prev,
2587            self._match_set(self.JOIN_KINDS) and self._prev,
2588        )
2589
2590    def _parse_join(
2591        self, skip_join_token: bool = False, parse_bracket: bool = False
2592    ) -> t.Optional[exp.Join]:
2593        if self._match(TokenType.COMMA):
2594            return self.expression(exp.Join, this=self._parse_table())
2595
2596        index = self._index
2597        method, side, kind = self._parse_join_parts()
2598        hint = self._prev.text if self._match_texts(self.JOIN_HINTS) else None
2599        join = self._match(TokenType.JOIN)
2600
2601        if not skip_join_token and not join:
2602            self._retreat(index)
2603            kind = None
2604            method = None
2605            side = None
2606
2607        outer_apply = self._match_pair(TokenType.OUTER, TokenType.APPLY, False)
2608        cross_apply = self._match_pair(TokenType.CROSS, TokenType.APPLY, False)
2609
2610        if not skip_join_token and not join and not outer_apply and not cross_apply:
2611            return None
2612
2613        kwargs: t.Dict[str, t.Any] = {"this": self._parse_table(parse_bracket=parse_bracket)}
2614
2615        if method:
2616            kwargs["method"] = method.text
2617        if side:
2618            kwargs["side"] = side.text
2619        if kind:
2620            kwargs["kind"] = kind.text
2621        if hint:
2622            kwargs["hint"] = hint
2623
2624        if self._match(TokenType.ON):
2625            kwargs["on"] = self._parse_conjunction()
2626        elif self._match(TokenType.USING):
2627            kwargs["using"] = self._parse_wrapped_id_vars()
2628        elif not (kind and kind.token_type == TokenType.CROSS):
2629            index = self._index
2630            join = self._parse_join()
2631
2632            if join and self._match(TokenType.ON):
2633                kwargs["on"] = self._parse_conjunction()
2634            elif join and self._match(TokenType.USING):
2635                kwargs["using"] = self._parse_wrapped_id_vars()
2636            else:
2637                join = None
2638                self._retreat(index)
2639
2640            kwargs["this"].set("joins", [join] if join else None)
2641
2642        comments = [c for token in (method, side, kind) if token for c in token.comments]
2643        return self.expression(exp.Join, comments=comments, **kwargs)
2644
2645    def _parse_opclass(self) -> t.Optional[exp.Expression]:
2646        this = self._parse_conjunction()
2647        if self._match_texts(self.OPCLASS_FOLLOW_KEYWORDS, advance=False):
2648            return this
2649
2650        if not self._match_set(self.OPTYPE_FOLLOW_TOKENS, advance=False):
2651            return self.expression(exp.Opclass, this=this, expression=self._parse_table_parts())
2652
2653        return this
2654
2655    def _parse_index(
2656        self,
2657        index: t.Optional[exp.Expression] = None,
2658    ) -> t.Optional[exp.Index]:
2659        if index:
2660            unique = None
2661            primary = None
2662            amp = None
2663
2664            self._match(TokenType.ON)
2665            self._match(TokenType.TABLE)  # hive
2666            table = self._parse_table_parts(schema=True)
2667        else:
2668            unique = self._match(TokenType.UNIQUE)
2669            primary = self._match_text_seq("PRIMARY")
2670            amp = self._match_text_seq("AMP")
2671
2672            if not self._match(TokenType.INDEX):
2673                return None
2674
2675            index = self._parse_id_var()
2676            table = None
2677
2678        using = self._parse_var(any_token=True) if self._match(TokenType.USING) else None
2679
2680        if self._match(TokenType.L_PAREN, advance=False):
2681            columns = self._parse_wrapped_csv(lambda: self._parse_ordered(self._parse_opclass))
2682        else:
2683            columns = None
2684
2685        return self.expression(
2686            exp.Index,
2687            this=index,
2688            table=table,
2689            using=using,
2690            columns=columns,
2691            unique=unique,
2692            primary=primary,
2693            amp=amp,
2694            partition_by=self._parse_partition_by(),
2695            where=self._parse_where(),
2696        )
2697
2698    def _parse_table_hints(self) -> t.Optional[t.List[exp.Expression]]:
2699        hints: t.List[exp.Expression] = []
2700        if self._match_pair(TokenType.WITH, TokenType.L_PAREN):
2701            # https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table?view=sql-server-ver16
2702            hints.append(
2703                self.expression(
2704                    exp.WithTableHint,
2705                    expressions=self._parse_csv(
2706                        lambda: self._parse_function() or self._parse_var(any_token=True)
2707                    ),
2708                )
2709            )
2710            self._match_r_paren()
2711        else:
2712            # https://dev.mysql.com/doc/refman/8.0/en/index-hints.html
2713            while self._match_set(self.TABLE_INDEX_HINT_TOKENS):
2714                hint = exp.IndexTableHint(this=self._prev.text.upper())
2715
2716                self._match_texts(("INDEX", "KEY"))
2717                if self._match(TokenType.FOR):
2718                    hint.set("target", self._advance_any() and self._prev.text.upper())
2719
2720                hint.set("expressions", self._parse_wrapped_id_vars())
2721                hints.append(hint)
2722
2723        return hints or None
2724
2725    def _parse_table_part(self, schema: bool = False) -> t.Optional[exp.Expression]:
2726        return (
2727            (not schema and self._parse_function(optional_parens=False))
2728            or self._parse_id_var(any_token=False)
2729            or self._parse_string_as_identifier()
2730            or self._parse_placeholder()
2731        )
2732
2733    def _parse_table_parts(self, schema: bool = False) -> exp.Table:
2734        catalog = None
2735        db = None
2736        table: t.Optional[exp.Expression | str] = self._parse_table_part(schema=schema)
2737
2738        while self._match(TokenType.DOT):
2739            if catalog:
2740                # This allows nesting the table in arbitrarily many dot expressions if needed
2741                table = self.expression(
2742                    exp.Dot, this=table, expression=self._parse_table_part(schema=schema)
2743                )
2744            else:
2745                catalog = db
2746                db = table
2747                table = self._parse_table_part(schema=schema) or ""
2748
2749        if not table:
2750            self.raise_error(f"Expected table name but got {self._curr}")
2751
2752        return self.expression(
2753            exp.Table, this=table, db=db, catalog=catalog, pivots=self._parse_pivots()
2754        )
2755
2756    def _parse_table(
2757        self,
2758        schema: bool = False,
2759        joins: bool = False,
2760        alias_tokens: t.Optional[t.Collection[TokenType]] = None,
2761        parse_bracket: bool = False,
2762    ) -> t.Optional[exp.Expression]:
2763        lateral = self._parse_lateral()
2764        if lateral:
2765            return lateral
2766
2767        unnest = self._parse_unnest()
2768        if unnest:
2769            return unnest
2770
2771        values = self._parse_derived_table_values()
2772        if values:
2773            return values
2774
2775        subquery = self._parse_select(table=True)
2776        if subquery:
2777            if not subquery.args.get("pivots"):
2778                subquery.set("pivots", self._parse_pivots())
2779            return subquery
2780
2781        bracket = parse_bracket and self._parse_bracket(None)
2782        bracket = self.expression(exp.Table, this=bracket) if bracket else None
2783        this = t.cast(
2784            exp.Expression, bracket or self._parse_bracket(self._parse_table_parts(schema=schema))
2785        )
2786
2787        if schema:
2788            return self._parse_schema(this=this)
2789
2790        version = self._parse_version()
2791
2792        if version:
2793            this.set("version", version)
2794
2795        if self.dialect.ALIAS_POST_TABLESAMPLE:
2796            table_sample = self._parse_table_sample()
2797
2798        alias = self._parse_table_alias(alias_tokens=alias_tokens or self.TABLE_ALIAS_TOKENS)
2799        if alias:
2800            this.set("alias", alias)
2801
2802        if isinstance(this, exp.Table) and self._match_text_seq("AT"):
2803            return self.expression(
2804                exp.AtIndex, this=this.to_column(copy=False), expression=self._parse_id_var()
2805            )
2806
2807        this.set("hints", self._parse_table_hints())
2808
2809        if not this.args.get("pivots"):
2810            this.set("pivots", self._parse_pivots())
2811
2812        if not self.dialect.ALIAS_POST_TABLESAMPLE:
2813            table_sample = self._parse_table_sample()
2814
2815        if table_sample:
2816            table_sample.set("this", this)
2817            this = table_sample
2818
2819        if joins:
2820            for join in iter(self._parse_join, None):
2821                this.append("joins", join)
2822
2823        if self._match_pair(TokenType.WITH, TokenType.ORDINALITY):
2824            this.set("ordinality", True)
2825            this.set("alias", self._parse_table_alias())
2826
2827        return this
2828
2829    def _parse_version(self) -> t.Optional[exp.Version]:
2830        if self._match(TokenType.TIMESTAMP_SNAPSHOT):
2831            this = "TIMESTAMP"
2832        elif self._match(TokenType.VERSION_SNAPSHOT):
2833            this = "VERSION"
2834        else:
2835            return None
2836
2837        if self._match_set((TokenType.FROM, TokenType.BETWEEN)):
2838            kind = self._prev.text.upper()
2839            start = self._parse_bitwise()
2840            self._match_texts(("TO", "AND"))
2841            end = self._parse_bitwise()
2842            expression: t.Optional[exp.Expression] = self.expression(
2843                exp.Tuple, expressions=[start, end]
2844            )
2845        elif self._match_text_seq("CONTAINED", "IN"):
2846            kind = "CONTAINED IN"
2847            expression = self.expression(
2848                exp.Tuple, expressions=self._parse_wrapped_csv(self._parse_bitwise)
2849            )
2850        elif self._match(TokenType.ALL):
2851            kind = "ALL"
2852            expression = None
2853        else:
2854            self._match_text_seq("AS", "OF")
2855            kind = "AS OF"
2856            expression = self._parse_type()
2857
2858        return self.expression(exp.Version, this=this, expression=expression, kind=kind)
2859
2860    def _parse_unnest(self, with_alias: bool = True) -> t.Optional[exp.Unnest]:
2861        if not self._match(TokenType.UNNEST):
2862            return None
2863
2864        expressions = self._parse_wrapped_csv(self._parse_equality)
2865        offset = self._match_pair(TokenType.WITH, TokenType.ORDINALITY)
2866
2867        alias = self._parse_table_alias() if with_alias else None
2868
2869        if alias:
2870            if self.dialect.UNNEST_COLUMN_ONLY:
2871                if alias.args.get("columns"):
2872                    self.raise_error("Unexpected extra column alias in unnest.")
2873
2874                alias.set("columns", [alias.this])
2875                alias.set("this", None)
2876
2877            columns = alias.args.get("columns") or []
2878            if offset and len(expressions) < len(columns):
2879                offset = columns.pop()
2880
2881        if not offset and self._match_pair(TokenType.WITH, TokenType.OFFSET):
2882            self._match(TokenType.ALIAS)
2883            offset = self._parse_id_var(
2884                any_token=False, tokens=self.UNNEST_OFFSET_ALIAS_TOKENS
2885            ) or exp.to_identifier("offset")
2886
2887        return self.expression(exp.Unnest, expressions=expressions, alias=alias, offset=offset)
2888
2889    def _parse_derived_table_values(self) -> t.Optional[exp.Values]:
2890        is_derived = self._match_pair(TokenType.L_PAREN, TokenType.VALUES)
2891        if not is_derived and not self._match(TokenType.VALUES):
2892            return None
2893
2894        expressions = self._parse_csv(self._parse_value)
2895        alias = self._parse_table_alias()
2896
2897        if is_derived:
2898            self._match_r_paren()
2899
2900        return self.expression(
2901            exp.Values, expressions=expressions, alias=alias or self._parse_table_alias()
2902        )
2903
2904    def _parse_table_sample(self, as_modifier: bool = False) -> t.Optional[exp.TableSample]:
2905        if not self._match(TokenType.TABLE_SAMPLE) and not (
2906            as_modifier and self._match_text_seq("USING", "SAMPLE")
2907        ):
2908            return None
2909
2910        bucket_numerator = None
2911        bucket_denominator = None
2912        bucket_field = None
2913        percent = None
2914        size = None
2915        seed = None
2916
2917        method = self._parse_var(tokens=(TokenType.ROW,), upper=True)
2918        matched_l_paren = self._match(TokenType.L_PAREN)
2919
2920        if self.TABLESAMPLE_CSV:
2921            num = None
2922            expressions = self._parse_csv(self._parse_primary)
2923        else:
2924            expressions = None
2925            num = (
2926                self._parse_factor()
2927                if self._match(TokenType.NUMBER, advance=False)
2928                else self._parse_primary() or self._parse_placeholder()
2929            )
2930
2931        if self._match_text_seq("BUCKET"):
2932            bucket_numerator = self._parse_number()
2933            self._match_text_seq("OUT", "OF")
2934            bucket_denominator = bucket_denominator = self._parse_number()
2935            self._match(TokenType.ON)
2936            bucket_field = self._parse_field()
2937        elif self._match_set((TokenType.PERCENT, TokenType.MOD)):
2938            percent = num
2939        elif self._match(TokenType.ROWS) or not self.dialect.TABLESAMPLE_SIZE_IS_PERCENT:
2940            size = num
2941        else:
2942            percent = num
2943
2944        if matched_l_paren:
2945            self._match_r_paren()
2946
2947        if self._match(TokenType.L_PAREN):
2948            method = self._parse_var(upper=True)
2949            seed = self._match(TokenType.COMMA) and self._parse_number()
2950            self._match_r_paren()
2951        elif self._match_texts(("SEED", "REPEATABLE")):
2952            seed = self._parse_wrapped(self._parse_number)
2953
2954        return self.expression(
2955            exp.TableSample,
2956            expressions=expressions,
2957            method=method,
2958            bucket_numerator=bucket_numerator,
2959            bucket_denominator=bucket_denominator,
2960            bucket_field=bucket_field,
2961            percent=percent,
2962            size=size,
2963            seed=seed,
2964        )
2965
2966    def _parse_pivots(self) -> t.Optional[t.List[exp.Pivot]]:
2967        return list(iter(self._parse_pivot, None)) or None
2968
2969    def _parse_joins(self) -> t.Optional[t.List[exp.Join]]:
2970        return list(iter(self._parse_join, None)) or None
2971
2972    # https://duckdb.org/docs/sql/statements/pivot
2973    def _parse_simplified_pivot(self) -> exp.Pivot:
2974        def _parse_on() -> t.Optional[exp.Expression]:
2975            this = self._parse_bitwise()
2976            return self._parse_in(this) if self._match(TokenType.IN) else this
2977
2978        this = self._parse_table()
2979        expressions = self._match(TokenType.ON) and self._parse_csv(_parse_on)
2980        using = self._match(TokenType.USING) and self._parse_csv(
2981            lambda: self._parse_alias(self._parse_function())
2982        )
2983        group = self._parse_group()
2984        return self.expression(
2985            exp.Pivot, this=this, expressions=expressions, using=using, group=group
2986        )
2987
2988    def _parse_pivot_in(self) -> exp.In:
2989        def _parse_aliased_expression() -> t.Optional[exp.Expression]:
2990            this = self._parse_conjunction()
2991
2992            self._match(TokenType.ALIAS)
2993            alias = self._parse_field()
2994            if alias:
2995                return self.expression(exp.PivotAlias, this=this, alias=alias)
2996
2997            return this
2998
2999        value = self._parse_column()
3000
3001        if not self._match_pair(TokenType.IN, TokenType.L_PAREN):
3002            self.raise_error("Expecting IN (")
3003
3004        aliased_expressions = self._parse_csv(_parse_aliased_expression)
3005
3006        self._match_r_paren()
3007        return self.expression(exp.In, this=value, expressions=aliased_expressions)
3008
3009    def _parse_pivot(self) -> t.Optional[exp.Pivot]:
3010        index = self._index
3011        include_nulls = None
3012
3013        if self._match(TokenType.PIVOT):
3014            unpivot = False
3015        elif self._match(TokenType.UNPIVOT):
3016            unpivot = True
3017
3018            # https://docs.databricks.com/en/sql/language-manual/sql-ref-syntax-qry-select-unpivot.html#syntax
3019            if self._match_text_seq("INCLUDE", "NULLS"):
3020                include_nulls = True
3021            elif self._match_text_seq("EXCLUDE", "NULLS"):
3022                include_nulls = False
3023        else:
3024            return None
3025
3026        expressions = []
3027
3028        if not self._match(TokenType.L_PAREN):
3029            self._retreat(index)
3030            return None
3031
3032        if unpivot:
3033            expressions = self._parse_csv(self._parse_column)
3034        else:
3035            expressions = self._parse_csv(lambda: self._parse_alias(self._parse_function()))
3036
3037        if not expressions:
3038            self.raise_error("Failed to parse PIVOT's aggregation list")
3039
3040        if not self._match(TokenType.FOR):
3041            self.raise_error("Expecting FOR")
3042
3043        field = self._parse_pivot_in()
3044
3045        self._match_r_paren()
3046
3047        pivot = self.expression(
3048            exp.Pivot,
3049            expressions=expressions,
3050            field=field,
3051            unpivot=unpivot,
3052            include_nulls=include_nulls,
3053        )
3054
3055        if not self._match_set((TokenType.PIVOT, TokenType.UNPIVOT), advance=False):
3056            pivot.set("alias", self._parse_table_alias())
3057
3058        if not unpivot:
3059            names = self._pivot_column_names(t.cast(t.List[exp.Expression], expressions))
3060
3061            columns: t.List[exp.Expression] = []
3062            for fld in pivot.args["field"].expressions:
3063                field_name = fld.sql() if self.IDENTIFY_PIVOT_STRINGS else fld.alias_or_name
3064                for name in names:
3065                    if self.PREFIXED_PIVOT_COLUMNS:
3066                        name = f"{name}_{field_name}" if name else field_name
3067                    else:
3068                        name = f"{field_name}_{name}" if name else field_name
3069
3070                    columns.append(exp.to_identifier(name))
3071
3072            pivot.set("columns", columns)
3073
3074        return pivot
3075
3076    def _pivot_column_names(self, aggregations: t.List[exp.Expression]) -> t.List[str]:
3077        return [agg.alias for agg in aggregations]
3078
3079    def _parse_where(self, skip_where_token: bool = False) -> t.Optional[exp.Where]:
3080        if not skip_where_token and not self._match(TokenType.WHERE):
3081            return None
3082
3083        return self.expression(
3084            exp.Where, comments=self._prev_comments, this=self._parse_conjunction()
3085        )
3086
3087    def _parse_group(self, skip_group_by_token: bool = False) -> t.Optional[exp.Group]:
3088        if not skip_group_by_token and not self._match(TokenType.GROUP_BY):
3089            return None
3090
3091        elements = defaultdict(list)
3092
3093        if self._match(TokenType.ALL):
3094            return self.expression(exp.Group, all=True)
3095
3096        while True:
3097            expressions = self._parse_csv(self._parse_conjunction)
3098            if expressions:
3099                elements["expressions"].extend(expressions)
3100
3101            grouping_sets = self._parse_grouping_sets()
3102            if grouping_sets:
3103                elements["grouping_sets"].extend(grouping_sets)
3104
3105            rollup = None
3106            cube = None
3107            totals = None
3108
3109            index = self._index
3110            with_ = self._match(TokenType.WITH)
3111            if self._match(TokenType.ROLLUP):
3112                rollup = with_ or self._parse_wrapped_csv(self._parse_column)
3113                elements["rollup"].extend(ensure_list(rollup))
3114
3115            if self._match(TokenType.CUBE):
3116                cube = with_ or self._parse_wrapped_csv(self._parse_column)
3117                elements["cube"].extend(ensure_list(cube))
3118
3119            if self._match_text_seq("TOTALS"):
3120                totals = True
3121                elements["totals"] = True  # type: ignore
3122
3123            if not (grouping_sets or rollup or cube or totals):
3124                if with_:
3125                    self._retreat(index)
3126                break
3127
3128        return self.expression(exp.Group, **elements)  # type: ignore
3129
3130    def _parse_grouping_sets(self) -> t.Optional[t.List[exp.Expression]]:
3131        if not self._match(TokenType.GROUPING_SETS):
3132            return None
3133
3134        return self._parse_wrapped_csv(self._parse_grouping_set)
3135
3136    def _parse_grouping_set(self) -> t.Optional[exp.Expression]:
3137        if self._match(TokenType.L_PAREN):
3138            grouping_set = self._parse_csv(self._parse_column)
3139            self._match_r_paren()
3140            return self.expression(exp.Tuple, expressions=grouping_set)
3141
3142        return self._parse_column()
3143
3144    def _parse_having(self, skip_having_token: bool = False) -> t.Optional[exp.Having]:
3145        if not skip_having_token and not self._match(TokenType.HAVING):
3146            return None
3147        return self.expression(exp.Having, this=self._parse_conjunction())
3148
3149    def _parse_qualify(self) -> t.Optional[exp.Qualify]:
3150        if not self._match(TokenType.QUALIFY):
3151            return None
3152        return self.expression(exp.Qualify, this=self._parse_conjunction())
3153
3154    def _parse_connect(self, skip_start_token: bool = False) -> t.Optional[exp.Connect]:
3155        if skip_start_token:
3156            start = None
3157        elif self._match(TokenType.START_WITH):
3158            start = self._parse_conjunction()
3159        else:
3160            return None
3161
3162        self._match(TokenType.CONNECT_BY)
3163        self.NO_PAREN_FUNCTION_PARSERS["PRIOR"] = lambda self: self.expression(
3164            exp.Prior, this=self._parse_bitwise()
3165        )
3166        connect = self._parse_conjunction()
3167        self.NO_PAREN_FUNCTION_PARSERS.pop("PRIOR")
3168
3169        if not start and self._match(TokenType.START_WITH):
3170            start = self._parse_conjunction()
3171
3172        return self.expression(exp.Connect, start=start, connect=connect)
3173
3174    def _parse_name_as_expression(self) -> exp.Alias:
3175        return self.expression(
3176            exp.Alias,
3177            alias=self._parse_id_var(any_token=True),
3178            this=self._match(TokenType.ALIAS) and self._parse_conjunction(),
3179        )
3180
3181    def _parse_interpolate(self) -> t.Optional[t.List[exp.Expression]]:
3182        if self._match_text_seq("INTERPOLATE"):
3183            return self._parse_wrapped_csv(self._parse_name_as_expression)
3184        return None
3185
3186    def _parse_order(
3187        self, this: t.Optional[exp.Expression] = None, skip_order_token: bool = False
3188    ) -> t.Optional[exp.Expression]:
3189        siblings = None
3190        if not skip_order_token and not self._match(TokenType.ORDER_BY):
3191            if not self._match(TokenType.ORDER_SIBLINGS_BY):
3192                return this
3193
3194            siblings = True
3195
3196        return self.expression(
3197            exp.Order,
3198            this=this,
3199            expressions=self._parse_csv(self._parse_ordered),
3200            interpolate=self._parse_interpolate(),
3201            siblings=siblings,
3202        )
3203
3204    def _parse_sort(self, exp_class: t.Type[E], token: TokenType) -> t.Optional[E]:
3205        if not self._match(token):
3206            return None
3207        return self.expression(exp_class, expressions=self._parse_csv(self._parse_ordered))
3208
3209    def _parse_ordered(self, parse_method: t.Optional[t.Callable] = None) -> exp.Ordered:
3210        this = parse_method() if parse_method else self._parse_conjunction()
3211
3212        asc = self._match(TokenType.ASC)
3213        desc = self._match(TokenType.DESC) or (asc and False)
3214
3215        is_nulls_first = self._match_text_seq("NULLS", "FIRST")
3216        is_nulls_last = self._match_text_seq("NULLS", "LAST")
3217
3218        nulls_first = is_nulls_first or False
3219        explicitly_null_ordered = is_nulls_first or is_nulls_last
3220
3221        if (
3222            not explicitly_null_ordered
3223            and (
3224                (not desc and self.dialect.NULL_ORDERING == "nulls_are_small")
3225                or (desc and self.dialect.NULL_ORDERING != "nulls_are_small")
3226            )
3227            and self.dialect.NULL_ORDERING != "nulls_are_last"
3228        ):
3229            nulls_first = True
3230
3231        if self._match_text_seq("WITH", "FILL"):
3232            with_fill = self.expression(
3233                exp.WithFill,
3234                **{  # type: ignore
3235                    "from": self._match(TokenType.FROM) and self._parse_bitwise(),
3236                    "to": self._match_text_seq("TO") and self._parse_bitwise(),
3237                    "step": self._match_text_seq("STEP") and self._parse_bitwise(),
3238                },
3239            )
3240        else:
3241            with_fill = None
3242
3243        return self.expression(
3244            exp.Ordered, this=this, desc=desc, nulls_first=nulls_first, with_fill=with_fill
3245        )
3246
3247    def _parse_limit(
3248        self, this: t.Optional[exp.Expression] = None, top: bool = False
3249    ) -> t.Optional[exp.Expression]:
3250        if self._match(TokenType.TOP if top else TokenType.LIMIT):
3251            comments = self._prev_comments
3252            if top:
3253                limit_paren = self._match(TokenType.L_PAREN)
3254                expression = self._parse_term() if limit_paren else self._parse_number()
3255
3256                if limit_paren:
3257                    self._match_r_paren()
3258            else:
3259                expression = self._parse_term()
3260
3261            if self._match(TokenType.COMMA):
3262                offset = expression
3263                expression = self._parse_term()
3264            else:
3265                offset = None
3266
3267            limit_exp = self.expression(
3268                exp.Limit, this=this, expression=expression, offset=offset, comments=comments
3269            )
3270
3271            return limit_exp
3272
3273        if self._match(TokenType.FETCH):
3274            direction = self._match_set((TokenType.FIRST, TokenType.NEXT))
3275            direction = self._prev.text.upper() if direction else "FIRST"
3276
3277            count = self._parse_field(tokens=self.FETCH_TOKENS)
3278            percent = self._match(TokenType.PERCENT)
3279
3280            self._match_set((TokenType.ROW, TokenType.ROWS))
3281
3282            only = self._match_text_seq("ONLY")
3283            with_ties = self._match_text_seq("WITH", "TIES")
3284
3285            if only and with_ties:
3286                self.raise_error("Cannot specify both ONLY and WITH TIES in FETCH clause")
3287
3288            return self.expression(
3289                exp.Fetch,
3290                direction=direction,
3291                count=count,
3292                percent=percent,
3293                with_ties=with_ties,
3294            )
3295
3296        return this
3297
3298    def _parse_offset(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
3299        if not self._match(TokenType.OFFSET):
3300            return this
3301
3302        count = self._parse_term()
3303        self._match_set((TokenType.ROW, TokenType.ROWS))
3304        return self.expression(exp.Offset, this=this, expression=count)
3305
3306    def _parse_locks(self) -> t.List[exp.Lock]:
3307        locks = []
3308        while True:
3309            if self._match_text_seq("FOR", "UPDATE"):
3310                update = True
3311            elif self._match_text_seq("FOR", "SHARE") or self._match_text_seq(
3312                "LOCK", "IN", "SHARE", "MODE"
3313            ):
3314                update = False
3315            else:
3316                break
3317
3318            expressions = None
3319            if self._match_text_seq("OF"):
3320                expressions = self._parse_csv(lambda: self._parse_table(schema=True))
3321
3322            wait: t.Optional[bool | exp.Expression] = None
3323            if self._match_text_seq("NOWAIT"):
3324                wait = True
3325            elif self._match_text_seq("WAIT"):
3326                wait = self._parse_primary()
3327            elif self._match_text_seq("SKIP", "LOCKED"):
3328                wait = False
3329
3330            locks.append(
3331                self.expression(exp.Lock, update=update, expressions=expressions, wait=wait)
3332            )
3333
3334        return locks
3335
3336    def _parse_set_operations(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3337        while this and self._match_set(self.SET_OPERATIONS):
3338            token_type = self._prev.token_type
3339
3340            if token_type == TokenType.UNION:
3341                operation = exp.Union
3342            elif token_type == TokenType.EXCEPT:
3343                operation = exp.Except
3344            else:
3345                operation = exp.Intersect
3346
3347            comments = self._prev.comments
3348            distinct = self._match(TokenType.DISTINCT) or not self._match(TokenType.ALL)
3349            by_name = self._match_text_seq("BY", "NAME")
3350            expression = self._parse_select(nested=True, parse_set_operation=False)
3351
3352            this = self.expression(
3353                operation,
3354                comments=comments,
3355                this=this,
3356                distinct=distinct,
3357                by_name=by_name,
3358                expression=expression,
3359            )
3360
3361        if isinstance(this, exp.Union) and self.MODIFIERS_ATTACHED_TO_UNION:
3362            expression = this.expression
3363
3364            if expression:
3365                for arg in self.UNION_MODIFIERS:
3366                    expr = expression.args.get(arg)
3367                    if expr:
3368                        this.set(arg, expr.pop())
3369
3370        return this
3371
3372    def _parse_expression(self) -> t.Optional[exp.Expression]:
3373        return self._parse_alias(self._parse_conjunction())
3374
3375    def _parse_conjunction(self) -> t.Optional[exp.Expression]:
3376        return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
3377
3378    def _parse_equality(self) -> t.Optional[exp.Expression]:
3379        return self._parse_tokens(self._parse_comparison, self.EQUALITY)
3380
3381    def _parse_comparison(self) -> t.Optional[exp.Expression]:
3382        return self._parse_tokens(self._parse_range, self.COMPARISON)
3383
3384    def _parse_range(self) -> t.Optional[exp.Expression]:
3385        this = self._parse_bitwise()
3386        negate = self._match(TokenType.NOT)
3387
3388        if self._match_set(self.RANGE_PARSERS):
3389            expression = self.RANGE_PARSERS[self._prev.token_type](self, this)
3390            if not expression:
3391                return this
3392
3393            this = expression
3394        elif self._match(TokenType.ISNULL):
3395            this = self.expression(exp.Is, this=this, expression=exp.Null())
3396
3397        # Postgres supports ISNULL and NOTNULL for conditions.
3398        # https://blog.andreiavram.ro/postgresql-null-composite-type/
3399        if self._match(TokenType.NOTNULL):
3400            this = self.expression(exp.Is, this=this, expression=exp.Null())
3401            this = self.expression(exp.Not, this=this)
3402
3403        if negate:
3404            this = self.expression(exp.Not, this=this)
3405
3406        if self._match(TokenType.IS):
3407            this = self._parse_is(this)
3408
3409        return this
3410
3411    def _parse_is(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3412        index = self._index - 1
3413        negate = self._match(TokenType.NOT)
3414
3415        if self._match_text_seq("DISTINCT", "FROM"):
3416            klass = exp.NullSafeEQ if negate else exp.NullSafeNEQ
3417            return self.expression(klass, this=this, expression=self._parse_conjunction())
3418
3419        expression = self._parse_null() or self._parse_boolean()
3420        if not expression:
3421            self._retreat(index)
3422            return None
3423
3424        this = self.expression(exp.Is, this=this, expression=expression)
3425        return self.expression(exp.Not, this=this) if negate else this
3426
3427    def _parse_in(self, this: t.Optional[exp.Expression], alias: bool = False) -> exp.In:
3428        unnest = self._parse_unnest(with_alias=False)
3429        if unnest:
3430            this = self.expression(exp.In, this=this, unnest=unnest)
3431        elif self._match_set((TokenType.L_PAREN, TokenType.L_BRACKET)):
3432            matched_l_paren = self._prev.token_type == TokenType.L_PAREN
3433            expressions = self._parse_csv(lambda: self._parse_select_or_expression(alias=alias))
3434
3435            if len(expressions) == 1 and isinstance(expressions[0], exp.Subqueryable):
3436                this = self.expression(exp.In, this=this, query=expressions[0])
3437            else:
3438                this = self.expression(exp.In, this=this, expressions=expressions)
3439
3440            if matched_l_paren:
3441                self._match_r_paren(this)
3442            elif not self._match(TokenType.R_BRACKET, expression=this):
3443                self.raise_error("Expecting ]")
3444        else:
3445            this = self.expression(exp.In, this=this, field=self._parse_field())
3446
3447        return this
3448
3449    def _parse_between(self, this: t.Optional[exp.Expression]) -> exp.Between:
3450        low = self._parse_bitwise()
3451        self._match(TokenType.AND)
3452        high = self._parse_bitwise()
3453        return self.expression(exp.Between, this=this, low=low, high=high)
3454
3455    def _parse_escape(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3456        if not self._match(TokenType.ESCAPE):
3457            return this
3458        return self.expression(exp.Escape, this=this, expression=self._parse_string())
3459
3460    def _parse_interval(self, match_interval: bool = True) -> t.Optional[exp.Interval]:
3461        index = self._index
3462
3463        if not self._match(TokenType.INTERVAL) and match_interval:
3464            return None
3465
3466        if self._match(TokenType.STRING, advance=False):
3467            this = self._parse_primary()
3468        else:
3469            this = self._parse_term()
3470
3471        if not this or (
3472            isinstance(this, exp.Column)
3473            and not this.table
3474            and not this.this.quoted
3475            and this.name.upper() == "IS"
3476        ):
3477            self._retreat(index)
3478            return None
3479
3480        unit = self._parse_function() or (
3481            not self._match(TokenType.ALIAS, advance=False)
3482            and self._parse_var(any_token=True, upper=True)
3483        )
3484
3485        # Most dialects support, e.g., the form INTERVAL '5' day, thus we try to parse
3486        # each INTERVAL expression into this canonical form so it's easy to transpile
3487        if this and this.is_number:
3488            this = exp.Literal.string(this.name)
3489        elif this and this.is_string:
3490            parts = this.name.split()
3491
3492            if len(parts) == 2:
3493                if unit:
3494                    # This is not actually a unit, it's something else (e.g. a "window side")
3495                    unit = None
3496                    self._retreat(self._index - 1)
3497
3498                this = exp.Literal.string(parts[0])
3499                unit = self.expression(exp.Var, this=parts[1].upper())
3500
3501        return self.expression(exp.Interval, this=this, unit=unit)
3502
3503    def _parse_bitwise(self) -> t.Optional[exp.Expression]:
3504        this = self._parse_term()
3505
3506        while True:
3507            if self._match_set(self.BITWISE):
3508                this = self.expression(
3509                    self.BITWISE[self._prev.token_type],
3510                    this=this,
3511                    expression=self._parse_term(),
3512                )
3513            elif self.dialect.DPIPE_IS_STRING_CONCAT and self._match(TokenType.DPIPE):
3514                this = self.expression(
3515                    exp.DPipe,
3516                    this=this,
3517                    expression=self._parse_term(),
3518                    safe=not self.dialect.STRICT_STRING_CONCAT,
3519                )
3520            elif self._match(TokenType.DQMARK):
3521                this = self.expression(exp.Coalesce, this=this, expressions=self._parse_term())
3522            elif self._match_pair(TokenType.LT, TokenType.LT):
3523                this = self.expression(
3524                    exp.BitwiseLeftShift, this=this, expression=self._parse_term()
3525                )
3526            elif self._match_pair(TokenType.GT, TokenType.GT):
3527                this = self.expression(
3528                    exp.BitwiseRightShift, this=this, expression=self._parse_term()
3529                )
3530            else:
3531                break
3532
3533        return this
3534
3535    def _parse_term(self) -> t.Optional[exp.Expression]:
3536        return self._parse_tokens(self._parse_factor, self.TERM)
3537
3538    def _parse_factor(self) -> t.Optional[exp.Expression]:
3539        if self.EXPONENT:
3540            factor = self._parse_tokens(self._parse_exponent, self.FACTOR)
3541        else:
3542            factor = self._parse_tokens(self._parse_unary, self.FACTOR)
3543        if isinstance(factor, exp.Div):
3544            factor.args["typed"] = self.dialect.TYPED_DIVISION
3545            factor.args["safe"] = self.dialect.SAFE_DIVISION
3546        return factor
3547
3548    def _parse_exponent(self) -> t.Optional[exp.Expression]:
3549        return self._parse_tokens(self._parse_unary, self.EXPONENT)
3550
3551    def _parse_unary(self) -> t.Optional[exp.Expression]:
3552        if self._match_set(self.UNARY_PARSERS):
3553            return self.UNARY_PARSERS[self._prev.token_type](self)
3554        return self._parse_at_time_zone(self._parse_type())
3555
3556    def _parse_type(self, parse_interval: bool = True) -> t.Optional[exp.Expression]:
3557        interval = parse_interval and self._parse_interval()
3558        if interval:
3559            # Convert INTERVAL 'val_1' unit_1 ... 'val_n' unit_n into a sum of intervals
3560            while self._match_set((TokenType.STRING, TokenType.NUMBER), advance=False):
3561                interval = self.expression(  # type: ignore
3562                    exp.Add, this=interval, expression=self._parse_interval(match_interval=False)
3563                )
3564
3565            return interval
3566
3567        index = self._index
3568        data_type = self._parse_types(check_func=True, allow_identifiers=False)
3569        this = self._parse_column()
3570
3571        if data_type:
3572            if isinstance(this, exp.Literal):
3573                parser = self.TYPE_LITERAL_PARSERS.get(data_type.this)
3574                if parser:
3575                    return parser(self, this, data_type)
3576                return self.expression(exp.Cast, this=this, to=data_type)
3577            if not data_type.expressions:
3578                self._retreat(index)
3579                return self._parse_column()
3580            return self._parse_column_ops(data_type)
3581
3582        return this and self._parse_column_ops(this)
3583
3584    def _parse_type_size(self) -> t.Optional[exp.DataTypeParam]:
3585        this = self._parse_type()
3586        if not this:
3587            return None
3588
3589        return self.expression(
3590            exp.DataTypeParam, this=this, expression=self._parse_var(any_token=True)
3591        )
3592
3593    def _parse_types(
3594        self, check_func: bool = False, schema: bool = False, allow_identifiers: bool = True
3595    ) -> t.Optional[exp.Expression]:
3596        index = self._index
3597
3598        prefix = self._match_text_seq("SYSUDTLIB", ".")
3599
3600        if not self._match_set(self.TYPE_TOKENS):
3601            identifier = allow_identifiers and self._parse_id_var(
3602                any_token=False, tokens=(TokenType.VAR,)
3603            )
3604
3605            if identifier:
3606                tokens = self.dialect.tokenize(identifier.name)
3607
3608                if len(tokens) != 1:
3609                    self.raise_error("Unexpected identifier", self._prev)
3610
3611                if tokens[0].token_type in self.TYPE_TOKENS:
3612                    self._prev = tokens[0]
3613                elif self.dialect.SUPPORTS_USER_DEFINED_TYPES:
3614                    type_name = identifier.name
3615
3616                    while self._match(TokenType.DOT):
3617                        type_name = f"{type_name}.{self._advance_any() and self._prev.text}"
3618
3619                    return exp.DataType.build(type_name, udt=True)
3620                else:
3621                    return None
3622            else:
3623                return None
3624
3625        type_token = self._prev.token_type
3626
3627        if type_token == TokenType.PSEUDO_TYPE:
3628            return self.expression(exp.PseudoType, this=self._prev.text.upper())
3629
3630        if type_token == TokenType.OBJECT_IDENTIFIER:
3631            return self.expression(exp.ObjectIdentifier, this=self._prev.text.upper())
3632
3633        nested = type_token in self.NESTED_TYPE_TOKENS
3634        is_struct = type_token in self.STRUCT_TYPE_TOKENS
3635        expressions = None
3636        maybe_func = False
3637
3638        if self._match(TokenType.L_PAREN):
3639            if is_struct:
3640                expressions = self._parse_csv(self._parse_struct_types)
3641            elif nested:
3642                expressions = self._parse_csv(
3643                    lambda: self._parse_types(
3644                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
3645                    )
3646                )
3647            elif type_token in self.ENUM_TYPE_TOKENS:
3648                expressions = self._parse_csv(self._parse_equality)
3649            else:
3650                expressions = self._parse_csv(self._parse_type_size)
3651
3652            if not expressions or not self._match(TokenType.R_PAREN):
3653                self._retreat(index)
3654                return None
3655
3656            maybe_func = True
3657
3658        this: t.Optional[exp.Expression] = None
3659        values: t.Optional[t.List[exp.Expression]] = None
3660
3661        if nested and self._match(TokenType.LT):
3662            if is_struct:
3663                expressions = self._parse_csv(lambda: self._parse_struct_types(type_required=True))
3664            else:
3665                expressions = self._parse_csv(
3666                    lambda: self._parse_types(
3667                        check_func=check_func, schema=schema, allow_identifiers=allow_identifiers
3668                    )
3669                )
3670
3671            if not self._match(TokenType.GT):
3672                self.raise_error("Expecting >")
3673
3674            if self._match_set((TokenType.L_BRACKET, TokenType.L_PAREN)):
3675                values = self._parse_csv(self._parse_conjunction)
3676                self._match_set((TokenType.R_BRACKET, TokenType.R_PAREN))
3677
3678        if type_token in self.TIMESTAMPS:
3679            if self._match_text_seq("WITH", "TIME", "ZONE"):
3680                maybe_func = False
3681                tz_type = (
3682                    exp.DataType.Type.TIMETZ
3683                    if type_token in self.TIMES
3684                    else exp.DataType.Type.TIMESTAMPTZ
3685                )
3686                this = exp.DataType(this=tz_type, expressions=expressions)
3687            elif self._match_text_seq("WITH", "LOCAL", "TIME", "ZONE"):
3688                maybe_func = False
3689                this = exp.DataType(this=exp.DataType.Type.TIMESTAMPLTZ, expressions=expressions)
3690            elif self._match_text_seq("WITHOUT", "TIME", "ZONE"):
3691                maybe_func = False
3692        elif type_token == TokenType.INTERVAL:
3693            unit = self._parse_var()
3694
3695            if self._match_text_seq("TO"):
3696                span = [exp.IntervalSpan(this=unit, expression=self._parse_var())]
3697            else:
3698                span = None
3699
3700            if span or not unit:
3701                this = self.expression(
3702                    exp.DataType, this=exp.DataType.Type.INTERVAL, expressions=span
3703                )
3704            else:
3705                this = self.expression(exp.DataType, this=self.expression(exp.Interval, unit=unit))
3706
3707        if maybe_func and check_func:
3708            index2 = self._index
3709            peek = self._parse_string()
3710
3711            if not peek:
3712                self._retreat(index)
3713                return None
3714
3715            self._retreat(index2)
3716
3717        if not this:
3718            if self._match_text_seq("UNSIGNED"):
3719                unsigned_type_token = self.SIGNED_TO_UNSIGNED_TYPE_TOKEN.get(type_token)
3720                if not unsigned_type_token:
3721                    self.raise_error(f"Cannot convert {type_token.value} to unsigned.")
3722
3723                type_token = unsigned_type_token or type_token
3724
3725            this = exp.DataType(
3726                this=exp.DataType.Type[type_token.value],
3727                expressions=expressions,
3728                nested=nested,
3729                values=values,
3730                prefix=prefix,
3731            )
3732
3733        while self._match_pair(TokenType.L_BRACKET, TokenType.R_BRACKET):
3734            this = exp.DataType(this=exp.DataType.Type.ARRAY, expressions=[this], nested=True)
3735
3736        return this
3737
3738    def _parse_struct_types(self, type_required: bool = False) -> t.Optional[exp.Expression]:
3739        index = self._index
3740        this = self._parse_type(parse_interval=False) or self._parse_id_var()
3741        self._match(TokenType.COLON)
3742        column_def = self._parse_column_def(this)
3743
3744        if type_required and (
3745            (isinstance(this, exp.Column) and this.this is column_def) or this is column_def
3746        ):
3747            self._retreat(index)
3748            return self._parse_types()
3749
3750        return column_def
3751
3752    def _parse_at_time_zone(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3753        if not self._match_text_seq("AT", "TIME", "ZONE"):
3754            return this
3755        return self.expression(exp.AtTimeZone, this=this, zone=self._parse_unary())
3756
3757    def _parse_column(self) -> t.Optional[exp.Expression]:
3758        this = self._parse_field()
3759        if isinstance(this, exp.Identifier):
3760            this = self.expression(exp.Column, this=this)
3761        elif not this:
3762            return self._parse_bracket(this)
3763        return self._parse_column_ops(this)
3764
3765    def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
3766        this = self._parse_bracket(this)
3767
3768        while self._match_set(self.COLUMN_OPERATORS):
3769            op_token = self._prev.token_type
3770            op = self.COLUMN_OPERATORS.get(op_token)
3771
3772            if op_token == TokenType.DCOLON:
3773                field = self._parse_types()
3774                if not field:
3775                    self.raise_error("Expected type")
3776            elif op and self._curr:
3777                self._advance()
3778                value = self._prev.text
3779                field = (
3780                    exp.Literal.number(value)
3781                    if self._prev.token_type == TokenType.NUMBER
3782                    else exp.Literal.string(value)
3783                )
3784            else:
3785                field = self._parse_field(anonymous_func=True, any_token=True)
3786
3787            if isinstance(field, exp.Func):
3788                # bigquery allows function calls like x.y.count(...)
3789                # SAFE.SUBSTR(...)
3790                # https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-reference#function_call_rules
3791                this = self._replace_columns_with_dots(this)
3792
3793            if op:
3794                this = op(self, this, field)
3795            elif isinstance(this, exp.Column) and not this.args.get("catalog"):
3796                this = self.expression(
3797                    exp.Column,
3798                    this=field,
3799                    table=this.this,
3800                    db=this.args.get("table"),
3801                    catalog=this.args.get("db"),
3802                )
3803            else:
3804                this = self.expression(exp.Dot, this=this, expression=field)
3805            this = self._parse_bracket(this)
3806        return this
3807
3808    def _parse_primary(self) -> t.Optional[exp.Expression]:
3809        if self._match_set(self.PRIMARY_PARSERS):
3810            token_type = self._prev.token_type
3811            primary = self.PRIMARY_PARSERS[token_type](self, self._prev)
3812
3813            if token_type == TokenType.STRING:
3814                expressions = [primary]
3815                while self._match(TokenType.STRING):
3816                    expressions.append(exp.Literal.string(self._prev.text))
3817
3818                if len(expressions) > 1:
3819                    return self.expression(exp.Concat, expressions=expressions)
3820
3821            return primary
3822
3823        if self._match_pair(TokenType.DOT, TokenType.NUMBER):
3824            return exp.Literal.number(f"0.{self._prev.text}")
3825
3826        if self._match(TokenType.L_PAREN):
3827            comments = self._prev_comments
3828            query = self._parse_select()
3829
3830            if query:
3831                expressions = [query]
3832            else:
3833                expressions = self._parse_expressions()
3834
3835            this = self._parse_query_modifiers(seq_get(expressions, 0))
3836
3837            if isinstance(this, exp.Subqueryable):
3838                this = self._parse_set_operations(
3839                    self._parse_subquery(this=this, parse_alias=False)
3840                )
3841            elif len(expressions) > 1:
3842                this = self.expression(exp.Tuple, expressions=expressions)
3843            else:
3844                this = self.expression(exp.Paren, this=self._parse_set_operations(this))
3845
3846            if this:
3847                this.add_comments(comments)
3848
3849            self._match_r_paren(expression=this)
3850            return this
3851
3852        return None
3853
3854    def _parse_field(
3855        self,
3856        any_token: bool = False,
3857        tokens: t.Optional[t.Collection[TokenType]] = None,
3858        anonymous_func: bool = False,
3859    ) -> t.Optional[exp.Expression]:
3860        return (
3861            self._parse_primary()
3862            or self._parse_function(anonymous=anonymous_func)
3863            or self._parse_id_var(any_token=any_token, tokens=tokens)
3864        )
3865
3866    def _parse_function(
3867        self,
3868        functions: t.Optional[t.Dict[str, t.Callable]] = None,
3869        anonymous: bool = False,
3870        optional_parens: bool = True,
3871    ) -> t.Optional[exp.Expression]:
3872        # This allows us to also parse {fn <function>} syntax (Snowflake, MySQL support this)
3873        # See: https://community.snowflake.com/s/article/SQL-Escape-Sequences
3874        fn_syntax = False
3875        if (
3876            self._match(TokenType.L_BRACE, advance=False)
3877            and self._next
3878            and self._next.text.upper() == "FN"
3879        ):
3880            self._advance(2)
3881            fn_syntax = True
3882
3883        func = self._parse_function_call(
3884            functions=functions, anonymous=anonymous, optional_parens=optional_parens
3885        )
3886
3887        if fn_syntax:
3888            self._match(TokenType.R_BRACE)
3889
3890        return func
3891
3892    def _parse_function_call(
3893        self,
3894        functions: t.Optional[t.Dict[str, t.Callable]] = None,
3895        anonymous: bool = False,
3896        optional_parens: bool = True,
3897    ) -> t.Optional[exp.Expression]:
3898        if not self._curr:
3899            return None
3900
3901        comments = self._curr.comments
3902        token_type = self._curr.token_type
3903        this = self._curr.text
3904        upper = this.upper()
3905
3906        parser = self.NO_PAREN_FUNCTION_PARSERS.get(upper)
3907        if optional_parens and parser and token_type not in self.INVALID_FUNC_NAME_TOKENS:
3908            self._advance()
3909            return parser(self)
3910
3911        if not self._next or self._next.token_type != TokenType.L_PAREN:
3912            if optional_parens and token_type in self.NO_PAREN_FUNCTIONS:
3913                self._advance()
3914                return self.expression(self.NO_PAREN_FUNCTIONS[token_type])
3915
3916            return None
3917
3918        if token_type not in self.FUNC_TOKENS:
3919            return None
3920
3921        self._advance(2)
3922
3923        parser = self.FUNCTION_PARSERS.get(upper)
3924        if parser and not anonymous:
3925            this = parser(self)
3926        else:
3927            subquery_predicate = self.SUBQUERY_PREDICATES.get(token_type)
3928
3929            if subquery_predicate and self._curr.token_type in (TokenType.SELECT, TokenType.WITH):
3930                this = self.expression(subquery_predicate, this=self._parse_select())
3931                self._match_r_paren()
3932                return this
3933
3934            if functions is None:
3935                functions = self.FUNCTIONS
3936
3937            function = functions.get(upper)
3938
3939            alias = upper in self.FUNCTIONS_WITH_ALIASED_ARGS
3940            args = self._parse_csv(lambda: self._parse_lambda(alias=alias))
3941
3942            if function and not anonymous:
3943                if "dialect" in function.__code__.co_varnames:
3944                    func = function(args, dialect=self.dialect)
3945                else:
3946                    func = function(args)
3947
3948                func = self.validate_expression(func, args)
3949                if not self.dialect.NORMALIZE_FUNCTIONS:
3950                    func.meta["name"] = this
3951
3952                this = func
3953            else:
3954                this = self.expression(exp.Anonymous, this=this, expressions=args)
3955
3956        if isinstance(this, exp.Expression):
3957            this.add_comments(comments)
3958
3959        self._match_r_paren(this)
3960        return self._parse_window(this)
3961
3962    def _parse_function_parameter(self) -> t.Optional[exp.Expression]:
3963        return self._parse_column_def(self._parse_id_var())
3964
3965    def _parse_user_defined_function(
3966        self, kind: t.Optional[TokenType] = None
3967    ) -> t.Optional[exp.Expression]:
3968        this = self._parse_id_var()
3969
3970        while self._match(TokenType.DOT):
3971            this = self.expression(exp.Dot, this=this, expression=self._parse_id_var())
3972
3973        if not self._match(TokenType.L_PAREN):
3974            return this
3975
3976        expressions = self._parse_csv(self._parse_function_parameter)
3977        self._match_r_paren()
3978        return self.expression(
3979            exp.UserDefinedFunction, this=this, expressions=expressions, wrapped=True
3980        )
3981
3982    def _parse_introducer(self, token: Token) -> exp.Introducer | exp.Identifier:
3983        literal = self._parse_primary()
3984        if literal:
3985            return self.expression(exp.Introducer, this=token.text, expression=literal)
3986
3987        return self.expression(exp.Identifier, this=token.text)
3988
3989    def _parse_session_parameter(self) -> exp.SessionParameter:
3990        kind = None
3991        this = self._parse_id_var() or self._parse_primary()
3992
3993        if this and self._match(TokenType.DOT):
3994            kind = this.name
3995            this = self._parse_var() or self._parse_primary()
3996
3997        return self.expression(exp.SessionParameter, this=this, kind=kind)
3998
3999    def _parse_lambda(self, alias: bool = False) -> t.Optional[exp.Expression]:
4000        index = self._index
4001
4002        if self._match(TokenType.L_PAREN):
4003            expressions = t.cast(
4004                t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_id_var)
4005            )
4006
4007            if not self._match(TokenType.R_PAREN):
4008                self._retreat(index)
4009        else:
4010            expressions = [self._parse_id_var()]
4011
4012        if self._match_set(self.LAMBDAS):
4013            return self.LAMBDAS[self._prev.token_type](self, expressions)
4014
4015        self._retreat(index)
4016
4017        this: t.Optional[exp.Expression]
4018
4019        if self._match(TokenType.DISTINCT):
4020            this = self.expression(
4021                exp.Distinct, expressions=self._parse_csv(self._parse_conjunction)
4022            )
4023        else:
4024            this = self._parse_select_or_expression(alias=alias)
4025
4026        return self._parse_limit(self._parse_order(self._parse_respect_or_ignore_nulls(this)))
4027
4028    def _parse_schema(self, this: t.Optional[exp.Expression] = None) -> t.Optional[exp.Expression]:
4029        index = self._index
4030
4031        if not self.errors:
4032            try:
4033                if self._parse_select(nested=True):
4034                    return this
4035            except ParseError:
4036                pass
4037            finally:
4038                self.errors.clear()
4039                self._retreat(index)
4040
4041        if not self._match(TokenType.L_PAREN):
4042            return this
4043
4044        args = self._parse_csv(lambda: self._parse_constraint() or self._parse_field_def())
4045
4046        self._match_r_paren()
4047        return self.expression(exp.Schema, this=this, expressions=args)
4048
4049    def _parse_field_def(self) -> t.Optional[exp.Expression]:
4050        return self._parse_column_def(self._parse_field(any_token=True))
4051
4052    def _parse_column_def(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4053        # column defs are not really columns, they're identifiers
4054        if isinstance(this, exp.Column):
4055            this = this.this
4056
4057        kind = self._parse_types(schema=True)
4058
4059        if self._match_text_seq("FOR", "ORDINALITY"):
4060            return self.expression(exp.ColumnDef, this=this, ordinality=True)
4061
4062        constraints: t.List[exp.Expression] = []
4063
4064        if not kind and self._match(TokenType.ALIAS):
4065            constraints.append(
4066                self.expression(
4067                    exp.ComputedColumnConstraint,
4068                    this=self._parse_conjunction(),
4069                    persisted=self._match_text_seq("PERSISTED"),
4070                    not_null=self._match_pair(TokenType.NOT, TokenType.NULL),
4071                )
4072            )
4073        elif kind and self._match_pair(TokenType.ALIAS, TokenType.L_PAREN, advance=False):
4074            self._match(TokenType.ALIAS)
4075            constraints.append(
4076                self.expression(exp.TransformColumnConstraint, this=self._parse_field())
4077            )
4078
4079        while True:
4080            constraint = self._parse_column_constraint()
4081            if not constraint:
4082                break
4083            constraints.append(constraint)
4084
4085        if not kind and not constraints:
4086            return this
4087
4088        return self.expression(exp.ColumnDef, this=this, kind=kind, constraints=constraints)
4089
4090    def _parse_auto_increment(
4091        self,
4092    ) -> exp.GeneratedAsIdentityColumnConstraint | exp.AutoIncrementColumnConstraint:
4093        start = None
4094        increment = None
4095
4096        if self._match(TokenType.L_PAREN, advance=False):
4097            args = self._parse_wrapped_csv(self._parse_bitwise)
4098            start = seq_get(args, 0)
4099            increment = seq_get(args, 1)
4100        elif self._match_text_seq("START"):
4101            start = self._parse_bitwise()
4102            self._match_text_seq("INCREMENT")
4103            increment = self._parse_bitwise()
4104
4105        if start and increment:
4106            return exp.GeneratedAsIdentityColumnConstraint(start=start, increment=increment)
4107
4108        return exp.AutoIncrementColumnConstraint()
4109
4110    def _parse_auto_property(self) -> t.Optional[exp.AutoRefreshProperty]:
4111        if not self._match_text_seq("REFRESH"):
4112            self._retreat(self._index - 1)
4113            return None
4114        return self.expression(exp.AutoRefreshProperty, this=self._parse_var(upper=True))
4115
4116    def _parse_compress(self) -> exp.CompressColumnConstraint:
4117        if self._match(TokenType.L_PAREN, advance=False):
4118            return self.expression(
4119                exp.CompressColumnConstraint, this=self._parse_wrapped_csv(self._parse_bitwise)
4120            )
4121
4122        return self.expression(exp.CompressColumnConstraint, this=self._parse_bitwise())
4123
4124    def _parse_generated_as_identity(
4125        self,
4126    ) -> (
4127        exp.GeneratedAsIdentityColumnConstraint
4128        | exp.ComputedColumnConstraint
4129        | exp.GeneratedAsRowColumnConstraint
4130    ):
4131        if self._match_text_seq("BY", "DEFAULT"):
4132            on_null = self._match_pair(TokenType.ON, TokenType.NULL)
4133            this = self.expression(
4134                exp.GeneratedAsIdentityColumnConstraint, this=False, on_null=on_null
4135            )
4136        else:
4137            self._match_text_seq("ALWAYS")
4138            this = self.expression(exp.GeneratedAsIdentityColumnConstraint, this=True)
4139
4140        self._match(TokenType.ALIAS)
4141
4142        if self._match_text_seq("ROW"):
4143            start = self._match_text_seq("START")
4144            if not start:
4145                self._match(TokenType.END)
4146            hidden = self._match_text_seq("HIDDEN")
4147            return self.expression(exp.GeneratedAsRowColumnConstraint, start=start, hidden=hidden)
4148
4149        identity = self._match_text_seq("IDENTITY")
4150
4151        if self._match(TokenType.L_PAREN):
4152            if self._match(TokenType.START_WITH):
4153                this.set("start", self._parse_bitwise())
4154            if self._match_text_seq("INCREMENT", "BY"):
4155                this.set("increment", self._parse_bitwise())
4156            if self._match_text_seq("MINVALUE"):
4157                this.set("minvalue", self._parse_bitwise())
4158            if self._match_text_seq("MAXVALUE"):
4159                this.set("maxvalue", self._parse_bitwise())
4160
4161            if self._match_text_seq("CYCLE"):
4162                this.set("cycle", True)
4163            elif self._match_text_seq("NO", "CYCLE"):
4164                this.set("cycle", False)
4165
4166            if not identity:
4167                this.set("expression", self._parse_bitwise())
4168            elif not this.args.get("start") and self._match(TokenType.NUMBER, advance=False):
4169                args = self._parse_csv(self._parse_bitwise)
4170                this.set("start", seq_get(args, 0))
4171                this.set("increment", seq_get(args, 1))
4172
4173            self._match_r_paren()
4174
4175        return this
4176
4177    def _parse_inline(self) -> exp.InlineLengthColumnConstraint:
4178        self._match_text_seq("LENGTH")
4179        return self.expression(exp.InlineLengthColumnConstraint, this=self._parse_bitwise())
4180
4181    def _parse_not_constraint(
4182        self,
4183    ) -> t.Optional[exp.Expression]:
4184        if self._match_text_seq("NULL"):
4185            return self.expression(exp.NotNullColumnConstraint)
4186        if self._match_text_seq("CASESPECIFIC"):
4187            return self.expression(exp.CaseSpecificColumnConstraint, not_=True)
4188        if self._match_text_seq("FOR", "REPLICATION"):
4189            return self.expression(exp.NotForReplicationColumnConstraint)
4190        return None
4191
4192    def _parse_column_constraint(self) -> t.Optional[exp.Expression]:
4193        if self._match(TokenType.CONSTRAINT):
4194            this = self._parse_id_var()
4195        else:
4196            this = None
4197
4198        if self._match_texts(self.CONSTRAINT_PARSERS):
4199            return self.expression(
4200                exp.ColumnConstraint,
4201                this=this,
4202                kind=self.CONSTRAINT_PARSERS[self._prev.text.upper()](self),
4203            )
4204
4205        return this
4206
4207    def _parse_constraint(self) -> t.Optional[exp.Expression]:
4208        if not self._match(TokenType.CONSTRAINT):
4209            return self._parse_unnamed_constraint(constraints=self.SCHEMA_UNNAMED_CONSTRAINTS)
4210
4211        this = self._parse_id_var()
4212        expressions = []
4213
4214        while True:
4215            constraint = self._parse_unnamed_constraint() or self._parse_function()
4216            if not constraint:
4217                break
4218            expressions.append(constraint)
4219
4220        return self.expression(exp.Constraint, this=this, expressions=expressions)
4221
4222    def _parse_unnamed_constraint(
4223        self, constraints: t.Optional[t.Collection[str]] = None
4224    ) -> t.Optional[exp.Expression]:
4225        if self._match(TokenType.IDENTIFIER, advance=False) or not self._match_texts(
4226            constraints or self.CONSTRAINT_PARSERS
4227        ):
4228            return None
4229
4230        constraint = self._prev.text.upper()
4231        if constraint not in self.CONSTRAINT_PARSERS:
4232            self.raise_error(f"No parser found for schema constraint {constraint}.")
4233
4234        return self.CONSTRAINT_PARSERS[constraint](self)
4235
4236    def _parse_unique(self) -> exp.UniqueColumnConstraint:
4237        self._match_text_seq("KEY")
4238        return self.expression(
4239            exp.UniqueColumnConstraint,
4240            this=self._parse_schema(self._parse_id_var(any_token=False)),
4241            index_type=self._match(TokenType.USING) and self._advance_any() and self._prev.text,
4242        )
4243
4244    def _parse_key_constraint_options(self) -> t.List[str]:
4245        options = []
4246        while True:
4247            if not self._curr:
4248                break
4249
4250            if self._match(TokenType.ON):
4251                action = None
4252                on = self._advance_any() and self._prev.text
4253
4254                if self._match_text_seq("NO", "ACTION"):
4255                    action = "NO ACTION"
4256                elif self._match_text_seq("CASCADE"):
4257                    action = "CASCADE"
4258                elif self._match_text_seq("RESTRICT"):
4259                    action = "RESTRICT"
4260                elif self._match_pair(TokenType.SET, TokenType.NULL):
4261                    action = "SET NULL"
4262                elif self._match_pair(TokenType.SET, TokenType.DEFAULT):
4263                    action = "SET DEFAULT"
4264                else:
4265                    self.raise_error("Invalid key constraint")
4266
4267                options.append(f"ON {on} {action}")
4268            elif self._match_text_seq("NOT", "ENFORCED"):
4269                options.append("NOT ENFORCED")
4270            elif self._match_text_seq("DEFERRABLE"):
4271                options.append("DEFERRABLE")
4272            elif self._match_text_seq("INITIALLY", "DEFERRED"):
4273                options.append("INITIALLY DEFERRED")
4274            elif self._match_text_seq("NORELY"):
4275                options.append("NORELY")
4276            elif self._match_text_seq("MATCH", "FULL"):
4277                options.append("MATCH FULL")
4278            else:
4279                break
4280
4281        return options
4282
4283    def _parse_references(self, match: bool = True) -> t.Optional[exp.Reference]:
4284        if match and not self._match(TokenType.REFERENCES):
4285            return None
4286
4287        expressions = None
4288        this = self._parse_table(schema=True)
4289        options = self._parse_key_constraint_options()
4290        return self.expression(exp.Reference, this=this, expressions=expressions, options=options)
4291
4292    def _parse_foreign_key(self) -> exp.ForeignKey:
4293        expressions = self._parse_wrapped_id_vars()
4294        reference = self._parse_references()
4295        options = {}
4296
4297        while self._match(TokenType.ON):
4298            if not self._match_set((TokenType.DELETE, TokenType.UPDATE)):
4299                self.raise_error("Expected DELETE or UPDATE")
4300
4301            kind = self._prev.text.lower()
4302
4303            if self._match_text_seq("NO", "ACTION"):
4304                action = "NO ACTION"
4305            elif self._match(TokenType.SET):
4306                self._match_set((TokenType.NULL, TokenType.DEFAULT))
4307                action = "SET " + self._prev.text.upper()
4308            else:
4309                self._advance()
4310                action = self._prev.text.upper()
4311
4312            options[kind] = action
4313
4314        return self.expression(
4315            exp.ForeignKey, expressions=expressions, reference=reference, **options  # type: ignore
4316        )
4317
4318    def _parse_primary_key_part(self) -> t.Optional[exp.Expression]:
4319        return self._parse_field()
4320
4321    def _parse_period_for_system_time(self) -> t.Optional[exp.PeriodForSystemTimeConstraint]:
4322        if not self._match(TokenType.TIMESTAMP_SNAPSHOT):
4323            self._retreat(self._index - 1)
4324            return None
4325
4326        id_vars = self._parse_wrapped_id_vars()
4327        return self.expression(
4328            exp.PeriodForSystemTimeConstraint,
4329            this=seq_get(id_vars, 0),
4330            expression=seq_get(id_vars, 1),
4331        )
4332
4333    def _parse_primary_key(
4334        self, wrapped_optional: bool = False, in_props: bool = False
4335    ) -> exp.PrimaryKeyColumnConstraint | exp.PrimaryKey:
4336        desc = (
4337            self._match_set((TokenType.ASC, TokenType.DESC))
4338            and self._prev.token_type == TokenType.DESC
4339        )
4340
4341        if not in_props and not self._match(TokenType.L_PAREN, advance=False):
4342            return self.expression(exp.PrimaryKeyColumnConstraint, desc=desc)
4343
4344        expressions = self._parse_wrapped_csv(
4345            self._parse_primary_key_part, optional=wrapped_optional
4346        )
4347        options = self._parse_key_constraint_options()
4348        return self.expression(exp.PrimaryKey, expressions=expressions, options=options)
4349
4350    def _parse_bracket_key_value(self, is_map: bool = False) -> t.Optional[exp.Expression]:
4351        return self._parse_slice(self._parse_alias(self._parse_conjunction(), explicit=True))
4352
4353    def _parse_bracket(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4354        if not self._match_set((TokenType.L_BRACKET, TokenType.L_BRACE)):
4355            return this
4356
4357        bracket_kind = self._prev.token_type
4358        expressions = self._parse_csv(
4359            lambda: self._parse_bracket_key_value(is_map=bracket_kind == TokenType.L_BRACE)
4360        )
4361
4362        if not self._match(TokenType.R_BRACKET) and bracket_kind == TokenType.L_BRACKET:
4363            self.raise_error("Expected ]")
4364        elif not self._match(TokenType.R_BRACE) and bracket_kind == TokenType.L_BRACE:
4365            self.raise_error("Expected }")
4366
4367        # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
4368        if bracket_kind == TokenType.L_BRACE:
4369            this = self.expression(exp.Struct, expressions=expressions)
4370        elif not this or this.name.upper() == "ARRAY":
4371            this = self.expression(exp.Array, expressions=expressions)
4372        else:
4373            expressions = apply_index_offset(this, expressions, -self.dialect.INDEX_OFFSET)
4374            this = self.expression(exp.Bracket, this=this, expressions=expressions)
4375
4376        self._add_comments(this)
4377        return self._parse_bracket(this)
4378
4379    def _parse_slice(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4380        if self._match(TokenType.COLON):
4381            return self.expression(exp.Slice, this=this, expression=self._parse_conjunction())
4382        return this
4383
4384    def _parse_case(self) -> t.Optional[exp.Expression]:
4385        ifs = []
4386        default = None
4387
4388        comments = self._prev_comments
4389        expression = self._parse_conjunction()
4390
4391        while self._match(TokenType.WHEN):
4392            this = self._parse_conjunction()
4393            self._match(TokenType.THEN)
4394            then = self._parse_conjunction()
4395            ifs.append(self.expression(exp.If, this=this, true=then))
4396
4397        if self._match(TokenType.ELSE):
4398            default = self._parse_conjunction()
4399
4400        if not self._match(TokenType.END):
4401            if isinstance(default, exp.Interval) and default.this.sql().upper() == "END":
4402                default = exp.column("interval")
4403            else:
4404                self.raise_error("Expected END after CASE", self._prev)
4405
4406        return self._parse_window(
4407            self.expression(exp.Case, comments=comments, this=expression, ifs=ifs, default=default)
4408        )
4409
4410    def _parse_if(self) -> t.Optional[exp.Expression]:
4411        if self._match(TokenType.L_PAREN):
4412            args = self._parse_csv(self._parse_conjunction)
4413            this = self.validate_expression(exp.If.from_arg_list(args), args)
4414            self._match_r_paren()
4415        else:
4416            index = self._index - 1
4417            condition = self._parse_conjunction()
4418
4419            if not condition:
4420                self._retreat(index)
4421                return None
4422
4423            self._match(TokenType.THEN)
4424            true = self._parse_conjunction()
4425            false = self._parse_conjunction() if self._match(TokenType.ELSE) else None
4426            self._match(TokenType.END)
4427            this = self.expression(exp.If, this=condition, true=true, false=false)
4428
4429        return self._parse_window(this)
4430
4431    def _parse_next_value_for(self) -> t.Optional[exp.Expression]:
4432        if not self._match_text_seq("VALUE", "FOR"):
4433            self._retreat(self._index - 1)
4434            return None
4435
4436        return self.expression(
4437            exp.NextValueFor,
4438            this=self._parse_column(),
4439            order=self._match(TokenType.OVER) and self._parse_wrapped(self._parse_order),
4440        )
4441
4442    def _parse_extract(self) -> exp.Extract:
4443        this = self._parse_function() or self._parse_var() or self._parse_type()
4444
4445        if self._match(TokenType.FROM):
4446            return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
4447
4448        if not self._match(TokenType.COMMA):
4449            self.raise_error("Expected FROM or comma after EXTRACT", self._prev)
4450
4451        return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
4452
4453    def _parse_any_value(self) -> exp.AnyValue:
4454        this = self._parse_lambda()
4455        is_max = None
4456        having = None
4457
4458        if self._match(TokenType.HAVING):
4459            self._match_texts(("MAX", "MIN"))
4460            is_max = self._prev.text == "MAX"
4461            having = self._parse_column()
4462
4463        return self.expression(exp.AnyValue, this=this, having=having, max=is_max)
4464
4465    def _parse_cast(self, strict: bool, safe: t.Optional[bool] = None) -> exp.Expression:
4466        this = self._parse_conjunction()
4467
4468        if not self._match(TokenType.ALIAS):
4469            if self._match(TokenType.COMMA):
4470                return self.expression(exp.CastToStrType, this=this, to=self._parse_string())
4471
4472            self.raise_error("Expected AS after CAST")
4473
4474        fmt = None
4475        to = self._parse_types()
4476
4477        if self._match(TokenType.FORMAT):
4478            fmt_string = self._parse_string()
4479            fmt = self._parse_at_time_zone(fmt_string)
4480
4481            if not to:
4482                to = exp.DataType.build(exp.DataType.Type.UNKNOWN)
4483            if to.this in exp.DataType.TEMPORAL_TYPES:
4484                this = self.expression(
4485                    exp.StrToDate if to.this == exp.DataType.Type.DATE else exp.StrToTime,
4486                    this=this,
4487                    format=exp.Literal.string(
4488                        format_time(
4489                            fmt_string.this if fmt_string else "",
4490                            self.dialect.FORMAT_MAPPING or self.dialect.TIME_MAPPING,
4491                            self.dialect.FORMAT_TRIE or self.dialect.TIME_TRIE,
4492                        )
4493                    ),
4494                )
4495
4496                if isinstance(fmt, exp.AtTimeZone) and isinstance(this, exp.StrToTime):
4497                    this.set("zone", fmt.args["zone"])
4498                return this
4499        elif not to:
4500            self.raise_error("Expected TYPE after CAST")
4501        elif isinstance(to, exp.Identifier):
4502            to = exp.DataType.build(to.name, udt=True)
4503        elif to.this == exp.DataType.Type.CHAR:
4504            if self._match(TokenType.CHARACTER_SET):
4505                to = self.expression(exp.CharacterSet, this=self._parse_var_or_string())
4506
4507        return self.expression(
4508            exp.Cast if strict else exp.TryCast, this=this, to=to, format=fmt, safe=safe
4509        )
4510
4511    def _parse_string_agg(self) -> exp.Expression:
4512        if self._match(TokenType.DISTINCT):
4513            args: t.List[t.Optional[exp.Expression]] = [
4514                self.expression(exp.Distinct, expressions=[self._parse_conjunction()])
4515            ]
4516            if self._match(TokenType.COMMA):
4517                args.extend(self._parse_csv(self._parse_conjunction))
4518        else:
4519            args = self._parse_csv(self._parse_conjunction)  # type: ignore
4520
4521        index = self._index
4522        if not self._match(TokenType.R_PAREN) and args:
4523            # postgres: STRING_AGG([DISTINCT] expression, separator [ORDER BY expression1 {ASC | DESC} [, ...]])
4524            # bigquery: STRING_AGG([DISTINCT] expression [, separator] [ORDER BY key [{ASC | DESC}] [, ... ]] [LIMIT n])
4525            args[-1] = self._parse_limit(this=self._parse_order(this=args[-1]))
4526            return self.expression(exp.GroupConcat, this=args[0], separator=seq_get(args, 1))
4527
4528        # Checks if we can parse an order clause: WITHIN GROUP (ORDER BY <order_by_expression_list> [ASC | DESC]).
4529        # This is done "manually", instead of letting _parse_window parse it into an exp.WithinGroup node, so that
4530        # the STRING_AGG call is parsed like in MySQL / SQLite and can thus be transpiled more easily to them.
4531        if not self._match_text_seq("WITHIN", "GROUP"):
4532            self._retreat(index)
4533            return self.validate_expression(exp.GroupConcat.from_arg_list(args), args)
4534
4535        self._match_l_paren()  # The corresponding match_r_paren will be called in parse_function (caller)
4536        order = self._parse_order(this=seq_get(args, 0))
4537        return self.expression(exp.GroupConcat, this=order, separator=seq_get(args, 1))
4538
4539    def _parse_convert(
4540        self, strict: bool, safe: t.Optional[bool] = None
4541    ) -> t.Optional[exp.Expression]:
4542        this = self._parse_bitwise()
4543
4544        if self._match(TokenType.USING):
4545            to: t.Optional[exp.Expression] = self.expression(
4546                exp.CharacterSet, this=self._parse_var()
4547            )
4548        elif self._match(TokenType.COMMA):
4549            to = self._parse_types()
4550        else:
4551            to = None
4552
4553        return self.expression(exp.Cast if strict else exp.TryCast, this=this, to=to, safe=safe)
4554
4555    def _parse_decode(self) -> t.Optional[exp.Decode | exp.Case]:
4556        """
4557        There are generally two variants of the DECODE function:
4558
4559        - DECODE(bin, charset)
4560        - DECODE(expression, search, result [, search, result] ... [, default])
4561
4562        The second variant will always be parsed into a CASE expression. Note that NULL
4563        needs special treatment, since we need to explicitly check for it with `IS NULL`,
4564        instead of relying on pattern matching.
4565        """
4566        args = self._parse_csv(self._parse_conjunction)
4567
4568        if len(args) < 3:
4569            return self.expression(exp.Decode, this=seq_get(args, 0), charset=seq_get(args, 1))
4570
4571        expression, *expressions = args
4572        if not expression:
4573            return None
4574
4575        ifs = []
4576        for search, result in zip(expressions[::2], expressions[1::2]):
4577            if not search or not result:
4578                return None
4579
4580            if isinstance(search, exp.Literal):
4581                ifs.append(
4582                    exp.If(this=exp.EQ(this=expression.copy(), expression=search), true=result)
4583                )
4584            elif isinstance(search, exp.Null):
4585                ifs.append(
4586                    exp.If(this=exp.Is(this=expression.copy(), expression=exp.Null()), true=result)
4587                )
4588            else:
4589                cond = exp.or_(
4590                    exp.EQ(this=expression.copy(), expression=search),
4591                    exp.and_(
4592                        exp.Is(this=expression.copy(), expression=exp.Null()),
4593                        exp.Is(this=search.copy(), expression=exp.Null()),
4594                        copy=False,
4595                    ),
4596                    copy=False,
4597                )
4598                ifs.append(exp.If(this=cond, true=result))
4599
4600        return exp.Case(ifs=ifs, default=expressions[-1] if len(expressions) % 2 == 1 else None)
4601
4602    def _parse_json_key_value(self) -> t.Optional[exp.JSONKeyValue]:
4603        self._match_text_seq("KEY")
4604        key = self._parse_column()
4605        self._match_set(self.JSON_KEY_VALUE_SEPARATOR_TOKENS)
4606        self._match_text_seq("VALUE")
4607        value = self._parse_bitwise()
4608
4609        if not key and not value:
4610            return None
4611        return self.expression(exp.JSONKeyValue, this=key, expression=value)
4612
4613    def _parse_format_json(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
4614        if not this or not self._match_text_seq("FORMAT", "JSON"):
4615            return this
4616
4617        return self.expression(exp.FormatJson, this=this)
4618
4619    def _parse_on_handling(self, on: str, *values: str) -> t.Optional[str]:
4620        # Parses the "X ON Y" syntax, i.e. NULL ON NULL (Oracle, T-SQL)
4621        for value in values:
4622            if self._match_text_seq(value, "ON", on):
4623                return f"{value} ON {on}"
4624
4625        return None
4626
4627    @t.overload
4628    def _parse_json_object(self, agg: Literal[False]) -> exp.JSONObject:
4629        ...
4630
4631    @t.overload
4632    def _parse_json_object(self, agg: Literal[True]) -> exp.JSONObjectAgg:
4633        ...
4634
4635    def _parse_json_object(self, agg=False):
4636        star = self._parse_star()
4637        expressions = (
4638            [star]
4639            if star
4640            else self._parse_csv(lambda: self._parse_format_json(self._parse_json_key_value()))
4641        )
4642        null_handling = self._parse_on_handling("NULL", "NULL", "ABSENT")
4643
4644        unique_keys = None
4645        if self._match_text_seq("WITH", "UNIQUE"):
4646            unique_keys = True
4647        elif self._match_text_seq("WITHOUT", "UNIQUE"):
4648            unique_keys = False
4649
4650        self._match_text_seq("KEYS")
4651
4652        return_type = self._match_text_seq("RETURNING") and self._parse_format_json(
4653            self._parse_type()
4654        )
4655        encoding = self._match_text_seq("ENCODING") and self._parse_var()
4656
4657        return self.expression(
4658            exp.JSONObjectAgg if agg else exp.JSONObject,
4659            expressions=expressions,
4660            null_handling=null_handling,
4661            unique_keys=unique_keys,
4662            return_type=return_type,
4663            encoding=encoding,
4664        )
4665
4666    # Note: this is currently incomplete; it only implements the "JSON_value_column" part
4667    def _parse_json_column_def(self) -> exp.JSONColumnDef:
4668        if not self._match_text_seq("NESTED"):
4669            this = self._parse_id_var()
4670            kind = self._parse_types(allow_identifiers=False)
4671            nested = None
4672        else:
4673            this = None
4674            kind = None
4675            nested = True
4676
4677        path = self._match_text_seq("PATH") and self._parse_string()
4678        nested_schema = nested and self._parse_json_schema()
4679
4680        return self.expression(
4681            exp.JSONColumnDef,
4682            this=this,
4683            kind=kind,
4684            path=path,
4685            nested_schema=nested_schema,
4686        )
4687
4688    def _parse_json_schema(self) -> exp.JSONSchema:
4689        self._match_text_seq("COLUMNS")
4690        return self.expression(
4691            exp.JSONSchema,
4692            expressions=self._parse_wrapped_csv(self._parse_json_column_def, optional=True),
4693        )
4694
4695    def _parse_json_table(self) -> exp.JSONTable:
4696        this = self._parse_format_json(self._parse_bitwise())
4697        path = self._match(TokenType.COMMA) and self._parse_string()
4698        error_handling = self._parse_on_handling("ERROR", "ERROR", "NULL")
4699        empty_handling = self._parse_on_handling("EMPTY", "ERROR", "NULL")
4700        schema = self._parse_json_schema()
4701
4702        return exp.JSONTable(
4703            this=this,
4704            schema=schema,
4705            path=path,
4706            error_handling=error_handling,
4707            empty_handling=empty_handling,
4708        )
4709
4710    def _parse_match_against(self) -> exp.MatchAgainst:
4711        expressions = self._parse_csv(self._parse_column)
4712
4713        self._match_text_seq(")", "AGAINST", "(")
4714
4715        this = self._parse_string()
4716
4717        if self._match_text_seq("IN", "NATURAL", "LANGUAGE", "MODE"):
4718            modifier = "IN NATURAL LANGUAGE MODE"
4719            if self._match_text_seq("WITH", "QUERY", "EXPANSION"):
4720                modifier = f"{modifier} WITH QUERY EXPANSION"
4721        elif self._match_text_seq("IN", "BOOLEAN", "MODE"):
4722            modifier = "IN BOOLEAN MODE"
4723        elif self._match_text_seq("WITH", "QUERY", "EXPANSION"):
4724            modifier = "WITH QUERY EXPANSION"
4725        else:
4726            modifier = None
4727
4728        return self.expression(
4729            exp.MatchAgainst, this=this, expressions=expressions, modifier=modifier
4730        )
4731
4732    # https://learn.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql?view=sql-server-ver16
4733    def _parse_open_json(self) -> exp.OpenJSON:
4734        this = self._parse_bitwise()
4735        path = self._match(TokenType.COMMA) and self._parse_string()
4736
4737        def _parse_open_json_column_def() -> exp.OpenJSONColumnDef:
4738            this = self._parse_field(any_token=True)
4739            kind = self._parse_types()
4740            path = self._parse_string()
4741            as_json = self._match_pair(TokenType.ALIAS, TokenType.JSON)
4742
4743            return self.expression(
4744                exp.OpenJSONColumnDef, this=this, kind=kind, path=path, as_json=as_json
4745            )
4746
4747        expressions = None
4748        if self._match_pair(TokenType.R_PAREN, TokenType.WITH):
4749            self._match_l_paren()
4750            expressions = self._parse_csv(_parse_open_json_column_def)
4751
4752        return self.expression(exp.OpenJSON, this=this, path=path, expressions=expressions)
4753
4754    def _parse_position(self, haystack_first: bool = False) -> exp.StrPosition:
4755        args = self._parse_csv(self._parse_bitwise)
4756
4757        if self._match(TokenType.IN):
4758            return self.expression(
4759                exp.StrPosition, this=self._parse_bitwise(), substr=seq_get(args, 0)
4760            )
4761
4762        if haystack_first:
4763            haystack = seq_get(args, 0)
4764            needle = seq_get(args, 1)
4765        else:
4766            needle = seq_get(args, 0)
4767            haystack = seq_get(args, 1)
4768
4769        return self.expression(
4770            exp.StrPosition, this=haystack, substr=needle, position=seq_get(args, 2)
4771        )
4772
4773    def _parse_predict(self) -> exp.Predict:
4774        self._match_text_seq("MODEL")
4775        this = self._parse_table()
4776
4777        self._match(TokenType.COMMA)
4778        self._match_text_seq("TABLE")
4779
4780        return self.expression(
4781            exp.Predict,
4782            this=this,
4783            expression=self._parse_table(),
4784            params_struct=self._match(TokenType.COMMA) and self._parse_bitwise(),
4785        )
4786
4787    def _parse_join_hint(self, func_name: str) -> exp.JoinHint:
4788        args = self._parse_csv(self._parse_table)
4789        return exp.JoinHint(this=func_name.upper(), expressions=args)
4790
4791    def _parse_substring(self) -> exp.Substring:
4792        # Postgres supports the form: substring(string [from int] [for int])
4793        # https://www.postgresql.org/docs/9.1/functions-string.html @ Table 9-6
4794
4795        args = t.cast(t.List[t.Optional[exp.Expression]], self._parse_csv(self._parse_bitwise))
4796
4797        if self._match(TokenType.FROM):
4798            args.append(self._parse_bitwise())
4799            if self._match(TokenType.FOR):
4800                args.append(self._parse_bitwise())
4801
4802        return self.validate_expression(exp.Substring.from_arg_list(args), args)
4803
4804    def _parse_trim(self) -> exp.Trim:
4805        # https://www.w3resource.com/sql/character-functions/trim.php
4806        # https://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
4807
4808        position = None
4809        collation = None
4810        expression = None
4811
4812        if self._match_texts(self.TRIM_TYPES):
4813            position = self._prev.text.upper()
4814
4815        this = self._parse_bitwise()
4816        if self._match_set((TokenType.FROM, TokenType.COMMA)):
4817            invert_order = self._prev.token_type == TokenType.FROM or self.TRIM_PATTERN_FIRST
4818            expression = self._parse_bitwise()
4819
4820            if invert_order:
4821                this, expression = expression, this
4822
4823        if self._match(TokenType.COLLATE):
4824            collation = self._parse_bitwise()
4825
4826        return self.expression(
4827            exp.Trim, this=this, position=position, expression=expression, collation=collation
4828        )
4829
4830    def _parse_window_clause(self) -> t.Optional[t.List[exp.Expression]]:
4831        return self._match(TokenType.WINDOW) and self._parse_csv(self._parse_named_window)
4832
4833    def _parse_named_window(self) -> t.Optional[exp.Expression]:
4834        return self._parse_window(self._parse_id_var(), alias=True)
4835
4836    def _parse_respect_or_ignore_nulls(
4837        self, this: t.Optional[exp.Expression]
4838    ) -> t.Optional[exp.Expression]:
4839        if self._match_text_seq("IGNORE", "NULLS"):
4840            return self.expression(exp.IgnoreNulls, this=this)
4841        if self._match_text_seq("RESPECT", "NULLS"):
4842            return self.expression(exp.RespectNulls, this=this)
4843        return this
4844
4845    def _parse_window(
4846        self, this: t.Optional[exp.Expression], alias: bool = False
4847    ) -> t.Optional[exp.Expression]:
4848        if self._match_pair(TokenType.FILTER, TokenType.L_PAREN):
4849            self._match(TokenType.WHERE)
4850            this = self.expression(
4851                exp.Filter, this=this, expression=self._parse_where(skip_where_token=True)
4852            )
4853            self._match_r_paren()
4854
4855        # T-SQL allows the OVER (...) syntax after WITHIN GROUP.
4856        # https://learn.microsoft.com/en-us/sql/t-sql/functions/percentile-disc-transact-sql?view=sql-server-ver16
4857        if self._match_text_seq("WITHIN", "GROUP"):
4858            order = self._parse_wrapped(self._parse_order)
4859            this = self.expression(exp.WithinGroup, this=this, expression=order)
4860
4861        # SQL spec defines an optional [ { IGNORE | RESPECT } NULLS ] OVER
4862        # Some dialects choose to implement and some do not.
4863        # https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html
4864
4865        # There is some code above in _parse_lambda that handles
4866        #   SELECT FIRST_VALUE(TABLE.COLUMN IGNORE|RESPECT NULLS) OVER ...
4867
4868        # The below changes handle
4869        #   SELECT FIRST_VALUE(TABLE.COLUMN) IGNORE|RESPECT NULLS OVER ...
4870
4871        # Oracle allows both formats
4872        #   (https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/first_value.html)
4873        #   and Snowflake chose to do the same for familiarity
4874        #   https://docs.snowflake.com/en/sql-reference/functions/first_value.html#usage-notes
4875        this = self._parse_respect_or_ignore_nulls(this)
4876
4877        # bigquery select from window x AS (partition by ...)
4878        if alias:
4879            over = None
4880            self._match(TokenType.ALIAS)
4881        elif not self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS):
4882            return this
4883        else:
4884            over = self._prev.text.upper()
4885
4886        if not self._match(TokenType.L_PAREN):
4887            return self.expression(
4888                exp.Window, this=this, alias=self._parse_id_var(False), over=over
4889            )
4890
4891        window_alias = self._parse_id_var(any_token=False, tokens=self.WINDOW_ALIAS_TOKENS)
4892
4893        first = self._match(TokenType.FIRST)
4894        if self._match_text_seq("LAST"):
4895            first = False
4896
4897        partition, order = self._parse_partition_and_order()
4898        kind = self._match_set((TokenType.ROWS, TokenType.RANGE)) and self._prev.text
4899
4900        if kind:
4901            self._match(TokenType.BETWEEN)
4902            start = self._parse_window_spec()
4903            self._match(TokenType.AND)
4904            end = self._parse_window_spec()
4905
4906            spec = self.expression(
4907                exp.WindowSpec,
4908                kind=kind,
4909                start=start["value"],
4910                start_side=start["side"],
4911                end=end["value"],
4912                end_side=end["side"],
4913            )
4914        else:
4915            spec = None
4916
4917        self._match_r_paren()
4918
4919        window = self.expression(
4920            exp.Window,
4921            this=this,
4922            partition_by=partition,
4923            order=order,
4924            spec=spec,
4925            alias=window_alias,
4926            over=over,
4927            first=first,
4928        )
4929
4930        # This covers Oracle's FIRST/LAST syntax: aggregate KEEP (...) OVER (...)
4931        if self._match_set(self.WINDOW_BEFORE_PAREN_TOKENS, advance=False):
4932            return self._parse_window(window, alias=alias)
4933
4934        return window
4935
4936    def _parse_partition_and_order(
4937        self,
4938    ) -> t.Tuple[t.List[exp.Expression], t.Optional[exp.Expression]]:
4939        return self._parse_partition_by(), self._parse_order()
4940
4941    def _parse_window_spec(self) -> t.Dict[str, t.Optional[str | exp.Expression]]:
4942        self._match(TokenType.BETWEEN)
4943
4944        return {
4945            "value": (
4946                (self._match_text_seq("UNBOUNDED") and "UNBOUNDED")
4947                or (self._match_text_seq("CURRENT", "ROW") and "CURRENT ROW")
4948                or self._parse_bitwise()
4949            ),
4950            "side": self._match_texts(self.WINDOW_SIDES) and self._prev.text,
4951        }
4952
4953    def _parse_alias(
4954        self, this: t.Optional[exp.Expression], explicit: bool = False
4955    ) -> t.Optional[exp.Expression]:
4956        any_token = self._match(TokenType.ALIAS)
4957        comments = self._prev_comments
4958
4959        if explicit and not any_token:
4960            return this
4961
4962        if self._match(TokenType.L_PAREN):
4963            aliases = self.expression(
4964                exp.Aliases,
4965                comments=comments,
4966                this=this,
4967                expressions=self._parse_csv(lambda: self._parse_id_var(any_token)),
4968            )
4969            self._match_r_paren(aliases)
4970            return aliases
4971
4972        alias = self._parse_id_var(any_token) or (
4973            self.STRING_ALIASES and self._parse_string_as_identifier()
4974        )
4975
4976        if alias:
4977            this = self.expression(exp.Alias, comments=comments, this=this, alias=alias)
4978
4979            # Moves the comment next to the alias in `expr /* comment */ AS alias`
4980            if not this.comments and this.this.comments:
4981                this.comments = this.this.comments
4982                this.this.comments = None
4983
4984        return this
4985
4986    def _parse_id_var(
4987        self,
4988        any_token: bool = True,
4989        tokens: t.Optional[t.Collection[TokenType]] = None,
4990    ) -> t.Optional[exp.Expression]:
4991        identifier = self._parse_identifier()
4992
4993        if identifier:
4994            return identifier
4995
4996        if (any_token and self._advance_any()) or self._match_set(tokens or self.ID_VAR_TOKENS):
4997            quoted = self._prev.token_type == TokenType.STRING
4998            return exp.Identifier(this=self._prev.text, quoted=quoted)
4999
5000        return None
5001
5002    def _parse_string(self) -> t.Optional[exp.Expression]:
5003        if self._match_set((TokenType.STRING, TokenType.RAW_STRING)):
5004            return self.PRIMARY_PARSERS[self._prev.token_type](self, self._prev)
5005        return self._parse_placeholder()
5006
5007    def _parse_string_as_identifier(self) -> t.Optional[exp.Identifier]:
5008        return exp.to_identifier(self._match(TokenType.STRING) and self._prev.text, quoted=True)
5009
5010    def _parse_number(self) -> t.Optional[exp.Expression]:
5011        if self._match(TokenType.NUMBER):
5012            return self.PRIMARY_PARSERS[TokenType.NUMBER](self, self._prev)
5013        return self._parse_placeholder()
5014
5015    def _parse_identifier(self) -> t.Optional[exp.Expression]:
5016        if self._match(TokenType.IDENTIFIER):
5017            return self.expression(exp.Identifier, this=self._prev.text, quoted=True)
5018        return self._parse_placeholder()
5019
5020    def _parse_var(
5021        self,
5022        any_token: bool = False,
5023        tokens: t.Optional[t.Collection[TokenType]] = None,
5024        upper: bool = False,
5025    ) -> t.Optional[exp.Expression]:
5026        if (
5027            (any_token and self._advance_any())
5028            or self._match(TokenType.VAR)
5029            or (self._match_set(tokens) if tokens else False)
5030        ):
5031            return self.expression(
5032                exp.Var, this=self._prev.text.upper() if upper else self._prev.text
5033            )
5034        return self._parse_placeholder()
5035
5036    def _advance_any(self, ignore_reserved: bool = False) -> t.Optional[Token]:
5037        if self._curr and (ignore_reserved or self._curr.token_type not in self.RESERVED_TOKENS):
5038            self._advance()
5039            return self._prev
5040        return None
5041
5042    def _parse_var_or_string(self) -> t.Optional[exp.Expression]:
5043        return self._parse_var() or self._parse_string()
5044
5045    def _parse_null(self) -> t.Optional[exp.Expression]:
5046        if self._match_set(self.NULL_TOKENS):
5047            return self.PRIMARY_PARSERS[TokenType.NULL](self, self._prev)
5048        return self._parse_placeholder()
5049
5050    def _parse_boolean(self) -> t.Optional[exp.Expression]:
5051        if self._match(TokenType.TRUE):
5052            return self.PRIMARY_PARSERS[TokenType.TRUE](self, self._prev)
5053        if self._match(TokenType.FALSE):
5054            return self.PRIMARY_PARSERS[TokenType.FALSE](self, self._prev)
5055        return self._parse_placeholder()
5056
5057    def _parse_star(self) -> t.Optional[exp.Expression]:
5058        if self._match(TokenType.STAR):
5059            return self.PRIMARY_PARSERS[TokenType.STAR](self, self._prev)
5060        return self._parse_placeholder()
5061
5062    def _parse_parameter(self) -> exp.Parameter:
5063        def _parse_parameter_part() -> t.Optional[exp.Expression]:
5064            return (
5065                self._parse_identifier() or self._parse_primary() or self._parse_var(any_token=True)
5066            )
5067
5068        self._match(TokenType.L_BRACE)
5069        this = _parse_parameter_part()
5070        expression = self._match(TokenType.COLON) and _parse_parameter_part()
5071        self._match(TokenType.R_BRACE)
5072
5073        return self.expression(exp.Parameter, this=this, expression=expression)
5074
5075    def _parse_placeholder(self) -> t.Optional[exp.Expression]:
5076        if self._match_set(self.PLACEHOLDER_PARSERS):
5077            placeholder = self.PLACEHOLDER_PARSERS[self._prev.token_type](self)
5078            if placeholder:
5079                return placeholder
5080            self._advance(-1)
5081        return None
5082
5083    def _parse_except(self) -> t.Optional[t.List[exp.Expression]]:
5084        if not self._match(TokenType.EXCEPT):
5085            return None
5086        if self._match(TokenType.L_PAREN, advance=False):
5087            return self._parse_wrapped_csv(self._parse_column)
5088
5089        except_column = self._parse_column()
5090        return [except_column] if except_column else None
5091
5092    def _parse_replace(self) -> t.Optional[t.List[exp.Expression]]:
5093        if not self._match(TokenType.REPLACE):
5094            return None
5095        if self._match(TokenType.L_PAREN, advance=False):
5096            return self._parse_wrapped_csv(self._parse_expression)
5097
5098        replace_expression = self._parse_expression()
5099        return [replace_expression] if replace_expression else None
5100
5101    def _parse_csv(
5102        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA
5103    ) -> t.List[exp.Expression]:
5104        parse_result = parse_method()
5105        items = [parse_result] if parse_result is not None else []
5106
5107        while self._match(sep):
5108            self._add_comments(parse_result)
5109            parse_result = parse_method()
5110            if parse_result is not None:
5111                items.append(parse_result)
5112
5113        return items
5114
5115    def _parse_tokens(
5116        self, parse_method: t.Callable, expressions: t.Dict
5117    ) -> t.Optional[exp.Expression]:
5118        this = parse_method()
5119
5120        while self._match_set(expressions):
5121            this = self.expression(
5122                expressions[self._prev.token_type],
5123                this=this,
5124                comments=self._prev_comments,
5125                expression=parse_method(),
5126            )
5127
5128        return this
5129
5130    def _parse_wrapped_id_vars(self, optional: bool = False) -> t.List[exp.Expression]:
5131        return self._parse_wrapped_csv(self._parse_id_var, optional=optional)
5132
5133    def _parse_wrapped_csv(
5134        self, parse_method: t.Callable, sep: TokenType = TokenType.COMMA, optional: bool = False
5135    ) -> t.List[exp.Expression]:
5136        return self._parse_wrapped(
5137            lambda: self._parse_csv(parse_method, sep=sep), optional=optional
5138        )
5139
5140    def _parse_wrapped(self, parse_method: t.Callable, optional: bool = False) -> t.Any:
5141        wrapped = self._match(TokenType.L_PAREN)
5142        if not wrapped and not optional:
5143            self.raise_error("Expecting (")
5144        parse_result = parse_method()
5145        if wrapped:
5146            self._match_r_paren()
5147        return parse_result
5148
5149    def _parse_expressions(self) -> t.List[exp.Expression]:
5150        return self._parse_csv(self._parse_expression)
5151
5152    def _parse_select_or_expression(self, alias: bool = False) -> t.Optional[exp.Expression]:
5153        return self._parse_select() or self._parse_set_operations(
5154            self._parse_expression() if alias else self._parse_conjunction()
5155        )
5156
5157    def _parse_ddl_select(self) -> t.Optional[exp.Expression]:
5158        return self._parse_query_modifiers(
5159            self._parse_set_operations(self._parse_select(nested=True, parse_subquery_alias=False))
5160        )
5161
5162    def _parse_transaction(self) -> exp.Transaction | exp.Command:
5163        this = None
5164        if self._match_texts(self.TRANSACTION_KIND):
5165            this = self._prev.text
5166
5167        self._match_texts(("TRANSACTION", "WORK"))
5168
5169        modes = []
5170        while True:
5171            mode = []
5172            while self._match(TokenType.VAR):
5173                mode.append(self._prev.text)
5174
5175            if mode:
5176                modes.append(" ".join(mode))
5177            if not self._match(TokenType.COMMA):
5178                break
5179
5180        return self.expression(exp.Transaction, this=this, modes=modes)
5181
5182    def _parse_commit_or_rollback(self) -> exp.Commit | exp.Rollback:
5183        chain = None
5184        savepoint = None
5185        is_rollback = self._prev.token_type == TokenType.ROLLBACK
5186
5187        self._match_texts(("TRANSACTION", "WORK"))
5188
5189        if self._match_text_seq("TO"):
5190            self._match_text_seq("SAVEPOINT")
5191            savepoint = self._parse_id_var()
5192
5193        if self._match(TokenType.AND):
5194            chain = not self._match_text_seq("NO")
5195            self._match_text_seq("CHAIN")
5196
5197        if is_rollback:
5198            return self.expression(exp.Rollback, savepoint=savepoint)
5199
5200        return self.expression(exp.Commit, chain=chain)
5201
5202    def _parse_refresh(self) -> exp.Refresh:
5203        self._match(TokenType.TABLE)
5204        return self.expression(exp.Refresh, this=self._parse_string() or self._parse_table())
5205
5206    def _parse_add_column(self) -> t.Optional[exp.Expression]:
5207        if not self._match_text_seq("ADD"):
5208            return None
5209
5210        self._match(TokenType.COLUMN)
5211        exists_column = self._parse_exists(not_=True)
5212        expression = self._parse_field_def()
5213
5214        if expression:
5215            expression.set("exists", exists_column)
5216
5217            # https://docs.databricks.com/delta/update-schema.html#explicitly-update-schema-to-add-columns
5218            if self._match_texts(("FIRST", "AFTER")):
5219                position = self._prev.text
5220                column_position = self.expression(
5221                    exp.ColumnPosition, this=self._parse_column(), position=position
5222                )
5223                expression.set("position", column_position)
5224
5225        return expression
5226
5227    def _parse_drop_column(self) -> t.Optional[exp.Drop | exp.Command]:
5228        drop = self._match(TokenType.DROP) and self._parse_drop()
5229        if drop and not isinstance(drop, exp.Command):
5230            drop.set("kind", drop.args.get("kind", "COLUMN"))
5231        return drop
5232
5233    # https://docs.aws.amazon.com/athena/latest/ug/alter-table-drop-partition.html
5234    def _parse_drop_partition(self, exists: t.Optional[bool] = None) -> exp.DropPartition:
5235        return self.expression(
5236            exp.DropPartition, expressions=self._parse_csv(self._parse_partition), exists=exists
5237        )
5238
5239    def _parse_add_constraint(self) -> exp.AddConstraint:
5240        this = None
5241        kind = self._prev.token_type
5242
5243        if kind == TokenType.CONSTRAINT:
5244            this = self._parse_id_var()
5245
5246            if self._match_text_seq("CHECK"):
5247                expression = self._parse_wrapped(self._parse_conjunction)
5248                enforced = self._match_text_seq("ENFORCED")
5249
5250                return self.expression(
5251                    exp.AddConstraint, this=this, expression=expression, enforced=enforced
5252                )
5253
5254        if kind == TokenType.FOREIGN_KEY or self._match(TokenType.FOREIGN_KEY):
5255            expression = self._parse_foreign_key()
5256        elif kind == TokenType.PRIMARY_KEY or self._match(TokenType.PRIMARY_KEY):
5257            expression = self._parse_primary_key()
5258        else:
5259            expression = None
5260
5261        return self.expression(exp.AddConstraint, this=this, expression=expression)
5262
5263    def _parse_alter_table_add(self) -> t.List[exp.Expression]:
5264        index = self._index - 1
5265
5266        if self._match_set(self.ADD_CONSTRAINT_TOKENS):
5267            return self._parse_csv(self._parse_add_constraint)
5268
5269        self._retreat(index)
5270        if not self.ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN and self._match_text_seq("ADD"):
5271            return self._parse_wrapped_csv(self._parse_field_def, optional=True)
5272        return self._parse_wrapped_csv(self._parse_add_column, optional=True)
5273
5274    def _parse_alter_table_alter(self) -> exp.AlterColumn:
5275        self._match(TokenType.COLUMN)
5276        column = self._parse_field(any_token=True)
5277
5278        if self._match_pair(TokenType.DROP, TokenType.DEFAULT):
5279            return self.expression(exp.AlterColumn, this=column, drop=True)
5280        if self._match_pair(TokenType.SET, TokenType.DEFAULT):
5281            return self.expression(exp.AlterColumn, this=column, default=self._parse_conjunction())
5282
5283        self._match_text_seq("SET", "DATA")
5284        return self.expression(
5285            exp.AlterColumn,
5286            this=column,
5287            dtype=self._match_text_seq("TYPE") and self._parse_types(),
5288            collate=self._match(TokenType.COLLATE) and self._parse_term(),
5289            using=self._match(TokenType.USING) and self._parse_conjunction(),
5290        )
5291
5292    def _parse_alter_table_drop(self) -> t.List[exp.Expression]:
5293        index = self._index - 1
5294
5295        partition_exists = self._parse_exists()
5296        if self._match(TokenType.PARTITION, advance=False):
5297            return self._parse_csv(lambda: self._parse_drop_partition(exists=partition_exists))
5298
5299        self._retreat(index)
5300        return self._parse_csv(self._parse_drop_column)
5301
5302    def _parse_alter_table_rename(self) -> exp.RenameTable:
5303        self._match_text_seq("TO")
5304        return self.expression(exp.RenameTable, this=self._parse_table(schema=True))
5305
5306    def _parse_alter(self) -> exp.AlterTable | exp.Command:
5307        start = self._prev
5308
5309        if not self._match(TokenType.TABLE):
5310            return self._parse_as_command(start)
5311
5312        exists = self._parse_exists()
5313        only = self._match_text_seq("ONLY")
5314        this = self._parse_table(schema=True)
5315
5316        if self._next:
5317            self._advance()
5318
5319        parser = self.ALTER_PARSERS.get(self._prev.text.upper()) if self._prev else None
5320        if parser:
5321            actions = ensure_list(parser(self))
5322
5323            if not self._curr:
5324                return self.expression(
5325                    exp.AlterTable,
5326                    this=this,
5327                    exists=exists,
5328                    actions=actions,
5329                    only=only,
5330                )
5331
5332        return self._parse_as_command(start)
5333
5334    def _parse_merge(self) -> exp.Merge:
5335        self._match(TokenType.INTO)
5336        target = self._parse_table()
5337
5338        if target and self._match(TokenType.ALIAS, advance=False):
5339            target.set("alias", self._parse_table_alias())
5340
5341        self._match(TokenType.USING)
5342        using = self._parse_table()
5343
5344        self._match(TokenType.ON)
5345        on = self._parse_conjunction()
5346
5347        return self.expression(
5348            exp.Merge,
5349            this=target,
5350            using=using,
5351            on=on,
5352            expressions=self._parse_when_matched(),
5353        )
5354
5355    def _parse_when_matched(self) -> t.List[exp.When]:
5356        whens = []
5357
5358        while self._match(TokenType.WHEN):
5359            matched = not self._match(TokenType.NOT)
5360            self._match_text_seq("MATCHED")
5361            source = (
5362                False
5363                if self._match_text_seq("BY", "TARGET")
5364                else self._match_text_seq("BY", "SOURCE")
5365            )
5366            condition = self._parse_conjunction() if self._match(TokenType.AND) else None
5367
5368            self._match(TokenType.THEN)
5369
5370            if self._match(TokenType.INSERT):
5371                _this = self._parse_star()
5372                if _this:
5373                    then: t.Optional[exp.Expression] = self.expression(exp.Insert, this=_this)
5374                else:
5375                    then = self.expression(
5376                        exp.Insert,
5377                        this=self._parse_value(),
5378                        expression=self._match(TokenType.VALUES) and self._parse_value(),
5379                    )
5380            elif self._match(TokenType.UPDATE):
5381                expressions = self._parse_star()
5382                if expressions:
5383                    then = self.expression(exp.Update, expressions=expressions)
5384                else:
5385                    then = self.expression(
5386                        exp.Update,
5387                        expressions=self._match(TokenType.SET)
5388                        and self._parse_csv(self._parse_equality),
5389                    )
5390            elif self._match(TokenType.DELETE):
5391                then = self.expression(exp.Var, this=self._prev.text)
5392            else:
5393                then = None
5394
5395            whens.append(
5396                self.expression(
5397                    exp.When,
5398                    matched=matched,
5399                    source=source,
5400                    condition=condition,
5401                    then=then,
5402                )
5403            )
5404        return whens
5405
5406    def _parse_show(self) -> t.Optional[exp.Expression]:
5407        parser = self._find_parser(self.SHOW_PARSERS, self.SHOW_TRIE)
5408        if parser:
5409            return parser(self)
5410        return self._parse_as_command(self._prev)
5411
5412    def _parse_set_item_assignment(
5413        self, kind: t.Optional[str] = None
5414    ) -> t.Optional[exp.Expression]:
5415        index = self._index
5416
5417        if kind in ("GLOBAL", "SESSION") and self._match_text_seq("TRANSACTION"):
5418            return self._parse_set_transaction(global_=kind == "GLOBAL")
5419
5420        left = self._parse_primary() or self._parse_id_var()
5421        assignment_delimiter = self._match_texts(("=", "TO"))
5422
5423        if not left or (self.SET_REQUIRES_ASSIGNMENT_DELIMITER and not assignment_delimiter):
5424            self._retreat(index)
5425            return None
5426
5427        right = self._parse_statement() or self._parse_id_var()
5428        this = self.expression(exp.EQ, this=left, expression=right)
5429
5430        return self.expression(exp.SetItem, this=this, kind=kind)
5431
5432    def _parse_set_transaction(self, global_: bool = False) -> exp.Expression:
5433        self._match_text_seq("TRANSACTION")
5434        characteristics = self._parse_csv(
5435            lambda: self._parse_var_from_options(self.TRANSACTION_CHARACTERISTICS)
5436        )
5437        return self.expression(
5438            exp.SetItem,
5439            expressions=characteristics,
5440            kind="TRANSACTION",
5441            **{"global": global_},  # type: ignore
5442        )
5443
5444    def _parse_set_item(self) -> t.Optional[exp.Expression]:
5445        parser = self._find_parser(self.SET_PARSERS, self.SET_TRIE)
5446        return parser(self) if parser else self._parse_set_item_assignment(kind=None)
5447
5448    def _parse_set(self, unset: bool = False, tag: bool = False) -> exp.Set | exp.Command:
5449        index = self._index
5450        set_ = self.expression(
5451            exp.Set, expressions=self._parse_csv(self._parse_set_item), unset=unset, tag=tag
5452        )
5453
5454        if self._curr:
5455            self._retreat(index)
5456            return self._parse_as_command(self._prev)
5457
5458        return set_
5459
5460    def _parse_var_from_options(self, options: t.Collection[str]) -> t.Optional[exp.Var]:
5461        for option in options:
5462            if self._match_text_seq(*option.split(" ")):
5463                return exp.var(option)
5464        return None
5465
5466    def _parse_as_command(self, start: Token) -> exp.Command:
5467        while self._curr:
5468            self._advance()
5469        text = self._find_sql(start, self._prev)
5470        size = len(start.text)
5471        return exp.Command(this=text[:size], expression=text[size:])
5472
5473    def _parse_dict_property(self, this: str) -> exp.DictProperty:
5474        settings = []
5475
5476        self._match_l_paren()
5477        kind = self._parse_id_var()
5478
5479        if self._match(TokenType.L_PAREN):
5480            while True:
5481                key = self._parse_id_var()
5482                value = self._parse_primary()
5483
5484                if not key and value is None:
5485                    break
5486                settings.append(self.expression(exp.DictSubProperty, this=key, value=value))
5487            self._match(TokenType.R_PAREN)
5488
5489        self._match_r_paren()
5490
5491        return self.expression(
5492            exp.DictProperty,
5493            this=this,
5494            kind=kind.this if kind else None,
5495            settings=settings,
5496        )
5497
5498    def _parse_dict_range(self, this: str) -> exp.DictRange:
5499        self._match_l_paren()
5500        has_min = self._match_text_seq("MIN")
5501        if has_min:
5502            min = self._parse_var() or self._parse_primary()
5503            self._match_text_seq("MAX")
5504            max = self._parse_var() or self._parse_primary()
5505        else:
5506            max = self._parse_var() or self._parse_primary()
5507            min = exp.Literal.number(0)
5508        self._match_r_paren()
5509        return self.expression(exp.DictRange, this=this, min=min, max=max)
5510
5511    def _parse_comprehension(
5512        self, this: t.Optional[exp.Expression]
5513    ) -> t.Optional[exp.Comprehension]:
5514        index = self._index
5515        expression = self._parse_column()
5516        if not self._match(TokenType.IN):
5517            self._retreat(index - 1)
5518            return None
5519        iterator = self._parse_column()
5520        condition = self._parse_conjunction() if self._match_text_seq("IF") else None
5521        return self.expression(
5522            exp.Comprehension,
5523            this=this,
5524            expression=expression,
5525            iterator=iterator,
5526            condition=condition,
5527        )
5528
5529    def _parse_heredoc(self) -> t.Optional[exp.Heredoc]:
5530        if self._match(TokenType.HEREDOC_STRING):
5531            return self.expression(exp.Heredoc, this=self._prev.text)
5532
5533        if not self._match_text_seq("$"):
5534            return None
5535
5536        tags = ["$"]
5537        tag_text = None
5538
5539        if self._is_connected():
5540            self._advance()
5541            tags.append(self._prev.text.upper())
5542        else:
5543            self.raise_error("No closing $ found")
5544
5545        if tags[-1] != "$":
5546            if self._is_connected() and self._match_text_seq("$"):
5547                tag_text = tags[-1]
5548                tags.append("$")
5549            else:
5550                self.raise_error("No closing $ found")
5551
5552        heredoc_start = self._curr
5553
5554        while self._curr:
5555            if self._match_text_seq(*tags, advance=False):
5556                this = self._find_sql(heredoc_start, self._prev)
5557                self._advance(len(tags))
5558                return self.expression(exp.Heredoc, this=this, tag=tag_text)
5559
5560            self._advance()
5561
5562        self.raise_error(f"No closing {''.join(tags)} found")
5563        return None
5564
5565    def _find_parser(
5566        self, parsers: t.Dict[str, t.Callable], trie: t.Dict
5567    ) -> t.Optional[t.Callable]:
5568        if not self._curr:
5569            return None
5570
5571        index = self._index
5572        this = []
5573        while True:
5574            # The current token might be multiple words
5575            curr = self._curr.text.upper()
5576            key = curr.split(" ")
5577            this.append(curr)
5578
5579            self._advance()
5580            result, trie = in_trie(trie, key)
5581            if result == TrieResult.FAILED:
5582                break
5583
5584            if result == TrieResult.EXISTS:
5585                subparser = parsers[" ".join(this)]
5586                return subparser
5587
5588        self._retreat(index)
5589        return None
5590
5591    def _match(self, token_type, advance=True, expression=None):
5592        if not self._curr:
5593            return None
5594
5595        if self._curr.token_type == token_type:
5596            if advance:
5597                self._advance()
5598            self._add_comments(expression)
5599            return True
5600
5601        return None
5602
5603    def _match_set(self, types, advance=True):
5604        if not self._curr:
5605            return None
5606
5607        if self._curr.token_type in types:
5608            if advance:
5609                self._advance()
5610            return True
5611
5612        return None
5613
5614    def _match_pair(self, token_type_a, token_type_b, advance=True):
5615        if not self._curr or not self._next:
5616            return None
5617
5618        if self._curr.token_type == token_type_a and self._next.token_type == token_type_b:
5619            if advance:
5620                self._advance(2)
5621            return True
5622
5623        return None
5624
5625    def _match_l_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
5626        if not self._match(TokenType.L_PAREN, expression=expression):
5627            self.raise_error("Expecting (")
5628
5629    def _match_r_paren(self, expression: t.Optional[exp.Expression] = None) -> None:
5630        if not self._match(TokenType.R_PAREN, expression=expression):
5631            self.raise_error("Expecting )")
5632
5633    def _match_texts(self, texts, advance=True):
5634        if self._curr and self._curr.text.upper() in texts:
5635            if advance:
5636                self._advance()
5637            return True
5638        return False
5639
5640    def _match_text_seq(self, *texts, advance=True):
5641        index = self._index
5642        for text in texts:
5643            if self._curr and self._curr.text.upper() == text:
5644                self._advance()
5645            else:
5646                self._retreat(index)
5647                return False
5648
5649        if not advance:
5650            self._retreat(index)
5651
5652        return True
5653
5654    @t.overload
5655    def _replace_columns_with_dots(self, this: exp.Expression) -> exp.Expression:
5656        ...
5657
5658    @t.overload
5659    def _replace_columns_with_dots(
5660        self, this: t.Optional[exp.Expression]
5661    ) -> t.Optional[exp.Expression]:
5662        ...
5663
5664    def _replace_columns_with_dots(self, this):
5665        if isinstance(this, exp.Dot):
5666            exp.replace_children(this, self._replace_columns_with_dots)
5667        elif isinstance(this, exp.Column):
5668            exp.replace_children(this, self._replace_columns_with_dots)
5669            table = this.args.get("table")
5670            this = (
5671                self.expression(exp.Dot, this=table, expression=this.this) if table else this.this
5672            )
5673
5674        return this
5675
5676    def _replace_lambda(
5677        self, node: t.Optional[exp.Expression], lambda_variables: t.Set[str]
5678    ) -> t.Optional[exp.Expression]:
5679        if not node:
5680            return node
5681
5682        for column in node.find_all(exp.Column):
5683            if column.parts[0].name in lambda_variables:
5684                dot_or_id = column.to_dot() if column.table else column.this
5685                parent = column.parent
5686
5687                while isinstance(parent, exp.Dot):
5688                    if not isinstance(parent.parent, exp.Dot):
5689                        parent.replace(dot_or_id)
5690                        break
5691                    parent = parent.parent
5692                else:
5693                    if column is node:
5694                        node = dot_or_id
5695                    else:
5696                        column.replace(dot_or_id)
5697        return node

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: Determines 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)
 996    def __init__(
 997        self,
 998        error_level: t.Optional[ErrorLevel] = None,
 999        error_message_context: int = 100,
1000        max_errors: int = 3,
1001        dialect: DialectType = None,
1002    ):
1003        from sqlglot.dialects import Dialect
1004
1005        self.error_level = error_level or ErrorLevel.IMMEDIATE
1006        self.error_message_context = error_message_context
1007        self.max_errors = max_errors
1008        self.dialect = Dialect.get_or_raise(dialect)
1009        self.reset()
FUNCTIONS: Dict[str, Callable] = {'ABS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Abs'>>, '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_CONTAINS': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayContains'>>, '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_JOIN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.ArrayJoin'>>, 'ARRAY_SIZE': <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_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'>>, '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>>, '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'>>, '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_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'>>, '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'>>, 'GENERATE_SERIES': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GenerateSeries'>>, 'GET_PATH': <bound method Func.from_arg_list of <class 'sqlglot.expressions.GetPath'>>, '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': <bound method Func.from_arg_list of <class 'sqlglot.expressions.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'>>, '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_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': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExtract'>>, 'JSON_EXTRACT_SCALAR': <bound method Func.from_arg_list of <class 'sqlglot.expressions.JSONExtractScalar'>>, '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'>>, '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'>>, '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'>>, 'LN': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Ln'>>, 'LOG': <function parse_logarithm>, 'LOG10': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Log10'>>, 'LOG2': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Log2'>>, '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': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, 'LCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Lower'>>, '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'>>, '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'>>, 'OPEN_J_S_O_N': <bound method Func.from_arg_list of <class 'sqlglot.expressions.OpenJSON'>>, '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'>>, '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'>>, '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'>>, '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'>>, '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_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'>>, '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'>>, '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_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'>>, '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'>>, 'UPPER': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Upper'>>, 'UCASE': <bound method Func.from_arg_list of <class 'sqlglot.expressions.Upper'>>, 'VAR_MAP': <function parse_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>>, 'LIKE': <function parse_like>}
NO_PAREN_FUNCTIONS = {<TokenType.CURRENT_DATE: 'CURRENT_DATE'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>: <class 'sqlglot.expressions.CurrentDate'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>: <class 'sqlglot.expressions.CurrentTime'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>: <class 'sqlglot.expressions.CurrentTimestamp'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>: <class 'sqlglot.expressions.CurrentUser'>}
STRUCT_TYPE_TOKENS = {<TokenType.STRUCT: 'STRUCT'>, <TokenType.NESTED: 'NESTED'>}
NESTED_TYPE_TOKENS = {<TokenType.NULLABLE: 'NULLABLE'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.MAP: 'MAP'>, <TokenType.NESTED: 'NESTED'>, <TokenType.STRUCT: 'STRUCT'>}
ENUM_TYPE_TOKENS = {<TokenType.ENUM: 'ENUM'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.ENUM8: 'ENUM8'>}
TYPE_TOKENS = {<TokenType.TSRANGE: 'TSRANGE'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.JSON: 'JSON'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INET: 'INET'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.INT256: 'INT256'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.BIT: 'BIT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.BINARY: 'BINARY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATE: 'DATE'>, <TokenType.INT: 'INT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MAP: 'MAP'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.YEAR: 'YEAR'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.XML: 'XML'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UINT: 'UINT'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.UUID: 'UUID'>, <TokenType.IPV6: 'IPV6'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>}
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.GT: 'GT'>, <TokenType.TILDA: 'TILDA'>, <TokenType.NOT: 'NOT'>, <TokenType.DASH: 'DASH'>, <TokenType.STAR: 'STAR'>, <TokenType.QUOTE: 'QUOTE'>, <TokenType.PLACEHOLDER: 'PLACEHOLDER'>, <TokenType.L_BRACE: 'L_BRACE'>, <TokenType.SELECT: 'SELECT'>, <TokenType.COMMA: 'COMMA'>, <TokenType.LT: 'LT'>, <TokenType.R_BRACE: 'R_BRACE'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.R_PAREN: 'R_PAREN'>, <TokenType.EQ: 'EQ'>, <TokenType.HASH: 'HASH'>, <TokenType.PLUS: 'PLUS'>, <TokenType.SEMICOLON: 'SEMICOLON'>, <TokenType.CARET: 'CARET'>, <TokenType.L_PAREN: 'L_PAREN'>, <TokenType.PARAMETER: 'PARAMETER'>, <TokenType.L_BRACKET: 'L_BRACKET'>, <TokenType.BACKSLASH: 'BACKSLASH'>, <TokenType.MOD: 'MOD'>, <TokenType.COLON: 'COLON'>, <TokenType.SLASH: 'SLASH'>, <TokenType.PIPE: 'PIPE'>, <TokenType.AMP: 'AMP'>, <TokenType.R_BRACKET: 'R_BRACKET'>, <TokenType.DOT: 'DOT'>}
DB_CREATABLES = {<TokenType.DATABASE: 'DATABASE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.VIEW: 'VIEW'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.MODEL: 'MODEL'>}
CREATABLES = {<TokenType.FUNCTION: 'FUNCTION'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.TABLE: 'TABLE'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.INDEX: 'INDEX'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.VIEW: 'VIEW'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.MODEL: 'MODEL'>}
ID_VAR_TOKENS = {<TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.JSON: 'JSON'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.APPLY: 'APPLY'>, <TokenType.SOME: 'SOME'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INET: 'INET'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.LEFT: 'LEFT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT256: 'INT256'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.KILL: 'KILL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FINAL: 'FINAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.BIT: 'BIT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ALL: 'ALL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.IS: 'IS'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ROW: 'ROW'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.END: 'END'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.VIEW: 'VIEW'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATE: 'DATE'>, <TokenType.INT: 'INT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MAP: 'MAP'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DIV: 'DIV'>, <TokenType.MONEY: 'MONEY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.DESC: 'DESC'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.XML: 'XML'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.USE: 'USE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UINT: 'UINT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ANY: 'ANY'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UUID: 'UUID'>, <TokenType.IPV6: 'IPV6'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FULL: 'FULL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SET: 'SET'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ASC: 'ASC'>, <TokenType.VAR: 'VAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.CASE: 'CASE'>, <TokenType.FIRST: 'FIRST'>}
INTERVAL_VARS = {<TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.JSON: 'JSON'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.APPLY: 'APPLY'>, <TokenType.SOME: 'SOME'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INET: 'INET'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.LEFT: 'LEFT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT256: 'INT256'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.KILL: 'KILL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FINAL: 'FINAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.BIT: 'BIT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ALL: 'ALL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.IS: 'IS'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ROW: 'ROW'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.VIEW: 'VIEW'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATE: 'DATE'>, <TokenType.INT: 'INT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MAP: 'MAP'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DIV: 'DIV'>, <TokenType.MONEY: 'MONEY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.DESC: 'DESC'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.XML: 'XML'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.USE: 'USE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UINT: 'UINT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ANY: 'ANY'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UUID: 'UUID'>, <TokenType.IPV6: 'IPV6'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FULL: 'FULL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SET: 'SET'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ASC: 'ASC'>, <TokenType.VAR: 'VAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.CASE: 'CASE'>, <TokenType.FIRST: 'FIRST'>}
TABLE_ALIAS_TOKENS = {<TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.JSON: 'JSON'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.SOME: 'SOME'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INET: 'INET'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT256: 'INT256'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.KILL: 'KILL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FINAL: 'FINAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.BIT: 'BIT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ALL: 'ALL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.IS: 'IS'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ROW: 'ROW'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.END: 'END'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATE: 'DATE'>, <TokenType.INT: 'INT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MAP: 'MAP'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DIV: 'DIV'>, <TokenType.MONEY: 'MONEY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.DESC: 'DESC'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.XML: 'XML'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.USE: 'USE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UINT: 'UINT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ANY: 'ANY'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UUID: 'UUID'>, <TokenType.IPV6: 'IPV6'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SET: 'SET'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ASC: 'ASC'>, <TokenType.VAR: 'VAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.CASE: 'CASE'>, <TokenType.FIRST: 'FIRST'>}
COMMENT_TABLE_ALIAS_TOKENS = {<TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.JSON: 'JSON'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.SOME: 'SOME'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INET: 'INET'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT256: 'INT256'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.KILL: 'KILL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FINAL: 'FINAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.BIT: 'BIT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ALL: 'ALL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ROW: 'ROW'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.END: 'END'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATE: 'DATE'>, <TokenType.INT: 'INT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MAP: 'MAP'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DIV: 'DIV'>, <TokenType.MONEY: 'MONEY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.DESC: 'DESC'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.XML: 'XML'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.USE: 'USE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UINT: 'UINT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ANY: 'ANY'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UUID: 'UUID'>, <TokenType.IPV6: 'IPV6'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SET: 'SET'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ASC: 'ASC'>, <TokenType.VAR: 'VAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.CASE: 'CASE'>, <TokenType.FIRST: 'FIRST'>}
UPDATE_ALIAS_TOKENS = {<TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.JSON: 'JSON'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.SOME: 'SOME'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INET: 'INET'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT256: 'INT256'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.KILL: 'KILL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FINAL: 'FINAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.BIT: 'BIT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ALL: 'ALL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.IS: 'IS'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ROW: 'ROW'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.END: 'END'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.VIEW: 'VIEW'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATE: 'DATE'>, <TokenType.INT: 'INT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MAP: 'MAP'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DIV: 'DIV'>, <TokenType.MONEY: 'MONEY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.DESC: 'DESC'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.XML: 'XML'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.USE: 'USE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UINT: 'UINT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ANY: 'ANY'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UUID: 'UUID'>, <TokenType.IPV6: 'IPV6'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.NEXT: 'NEXT'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ASC: 'ASC'>, <TokenType.VAR: 'VAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.CASE: 'CASE'>, <TokenType.FIRST: 'FIRST'>}
TRIM_TYPES = {'LEADING', 'BOTH', 'TRAILING'}
FUNC_TOKENS = {<TokenType.TSRANGE: 'TSRANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.ILIKE: 'ILIKE'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.JSON: 'JSON'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.SOME: 'SOME'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INET: 'INET'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.LEFT: 'LEFT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT256: 'INT256'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.IPV4: 'IPV4'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.BIT: 'BIT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.UNNEST: 'UNNEST'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.ALL: 'ALL'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.INSERT: 'INSERT'>, <TokenType.XOR: 'XOR'>, <TokenType.ROW: 'ROW'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TEXT: 'TEXT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.BINARY: 'BINARY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.RLIKE: 'RLIKE'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.DATE: 'DATE'>, <TokenType.INT: 'INT'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MAP: 'MAP'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.MONEY: 'MONEY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.YEAR: 'YEAR'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.XML: 'XML'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.FILTER: 'FILTER'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.GLOB: 'GLOB'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UINT: 'UINT'>, <TokenType.ANY: 'ANY'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.LIKE: 'LIKE'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UUID: 'UUID'>, <TokenType.IPV6: 'IPV6'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.VAR: 'VAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.FIRST: 'FIRST'>}
CONJUNCTION = {<TokenType.AND: 'AND'>: <class 'sqlglot.expressions.And'>, <TokenType.OR: 'OR'>: <class 'sqlglot.expressions.Or'>}
EQUALITY = {<TokenType.COLON_EQ: 'COLON_EQ'>: <class 'sqlglot.expressions.PropertyEQ'>, <TokenType.EQ: 'EQ'>: <class 'sqlglot.expressions.EQ'>, <TokenType.NEQ: 'NEQ'>: <class 'sqlglot.expressions.NEQ'>, <TokenType.NULLSAFE_EQ: 'NULLSAFE_EQ'>: <class 'sqlglot.expressions.NullSafeEQ'>}
COMPARISON = {<TokenType.GT: 'GT'>: <class 'sqlglot.expressions.GT'>, <TokenType.GTE: 'GTE'>: <class 'sqlglot.expressions.GTE'>, <TokenType.LT: 'LT'>: <class 'sqlglot.expressions.LT'>, <TokenType.LTE: 'LTE'>: <class 'sqlglot.expressions.LTE'>}
BITWISE = {<TokenType.AMP: 'AMP'>: <class 'sqlglot.expressions.BitwiseAnd'>, <TokenType.CARET: 'CARET'>: <class 'sqlglot.expressions.BitwiseXor'>, <TokenType.PIPE: 'PIPE'>: <class 'sqlglot.expressions.BitwiseOr'>}
TERM = {<TokenType.DASH: 'DASH'>: <class 'sqlglot.expressions.Sub'>, <TokenType.PLUS: 'PLUS'>: <class 'sqlglot.expressions.Add'>, <TokenType.MOD: 'MOD'>: <class 'sqlglot.expressions.Mod'>, <TokenType.COLLATE: 'COLLATE'>: <class 'sqlglot.expressions.Collate'>}
FACTOR = {<TokenType.DIV: 'DIV'>: <class 'sqlglot.expressions.IntDiv'>, <TokenType.LR_ARROW: 'LR_ARROW'>: <class 'sqlglot.expressions.Distance'>, <TokenType.SLASH: 'SLASH'>: <class 'sqlglot.expressions.Div'>, <TokenType.STAR: 'STAR'>: <class 'sqlglot.expressions.Mul'>}
TIMES = {<TokenType.TIME: 'TIME'>, <TokenType.TIMETZ: 'TIMETZ'>}
TIMESTAMPS = {<TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>}
SET_OPERATIONS = {<TokenType.EXCEPT: 'EXCEPT'>, <TokenType.INTERSECT: 'INTERSECT'>, <TokenType.UNION: 'UNION'>}
JOIN_METHODS = {<TokenType.NATURAL: 'NATURAL'>, <TokenType.ASOF: 'ASOF'>}
JOIN_SIDES = {<TokenType.LEFT: 'LEFT'>, <TokenType.FULL: 'FULL'>, <TokenType.RIGHT: 'RIGHT'>}
JOIN_KINDS = {<TokenType.SEMI: 'SEMI'>, <TokenType.ANTI: 'ANTI'>, <TokenType.CROSS: 'CROSS'>, <TokenType.INNER: 'INNER'>, <TokenType.OUTER: 'OUTER'>}
JOIN_HINTS: Set[str] = set()
LAMBDAS = {<TokenType.ARROW: 'ARROW'>: <function Parser.<lambda>>, <TokenType.FARROW: 'FARROW'>: <function Parser.<lambda>>}
COLUMN_OPERATORS = {<TokenType.DOT: 'DOT'>: None, <TokenType.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.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.COMMIT: 'COMMIT'>: <function Parser.<lambda>>, <TokenType.COMMENT: 'COMMENT'>: <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.UNCACHE: 'UNCACHE'>: <function Parser.<lambda>>, <TokenType.UPDATE: 'UPDATE'>: <function Parser.<lambda>>, <TokenType.USE: 'USE'>: <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>>}
PRIMARY_PARSERS = {<TokenType.STRING: 'STRING'>: <function Parser.<lambda>>, <TokenType.NUMBER: 'NUMBER'>: <function Parser.<lambda>>, <TokenType.STAR: 'STAR'>: <function Parser.<lambda>>, <TokenType.NULL: 'NULL'>: <function Parser.<lambda>>, <TokenType.TRUE: 'TRUE'>: <function Parser.<lambda>>, <TokenType.FALSE: 'FALSE'>: <function Parser.<lambda>>, <TokenType.BIT_STRING: 'BIT_STRING'>: <function Parser.<lambda>>, <TokenType.HEX_STRING: 'HEX_STRING'>: <function Parser.<lambda>>, <TokenType.BYTE_STRING: 'BYTE_STRING'>: <function Parser.<lambda>>, <TokenType.INTRODUCER: 'INTRODUCER'>: <function Parser.<lambda>>, <TokenType.NATIONAL_STRING: 'NATIONAL_STRING'>: <function Parser.<lambda>>, <TokenType.RAW_STRING: 'RAW_STRING'>: <function Parser.<lambda>>, <TokenType.HEREDOC_STRING: 'HEREDOC_STRING'>: <function Parser.<lambda>>, <TokenType.UNICODE_STRING: 'UNICODE_STRING'>: <function Parser.<lambda>>, <TokenType.SESSION_PARAMETER: 'SESSION_PARAMETER'>: <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>.<lambda>>, <TokenType.ILIKE: 'ILIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.IN: 'IN'>: <function Parser.<lambda>>, <TokenType.IRLIKE: 'IRLIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.IS: 'IS'>: <function Parser.<lambda>>, <TokenType.LIKE: 'LIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.OVERLAPS: 'OVERLAPS'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.RLIKE: 'RLIKE'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.SIMILAR_TO: 'SIMILAR_TO'>: <function binary_range_parser.<locals>.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>}
PROPERTY_PARSERS: Dict[str, Callable] = {'ALGORITHM': <function Parser.<lambda>>, 'AUTO': <function Parser.<lambda>>, 'AUTO_INCREMENT': <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>>, 'DEFINER': <function Parser.<lambda>>, 'DETERMINISTIC': <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>>, 'HEAP': <function Parser.<lambda>>, 'IMMUTABLE': <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>>, 'ROW': <function Parser.<lambda>>, 'ROW_FORMAT': <function Parser.<lambda>>, 'SAMPLE': <function Parser.<lambda>>, 'SET': <function Parser.<lambda>>, 'SETTINGS': <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>>, '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>>, '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>>, 'DELETE': <function Parser.<lambda>>, 'DROP': <function Parser.<lambda>>, 'RENAME': <function Parser.<lambda>>}
SCHEMA_UNNAMED_CONSTRAINTS = {'PRIMARY KEY', 'CHECK', 'PERIOD', 'UNIQUE', 'LIKE', 'FOREIGN KEY'}
NO_PAREN_FUNCTION_PARSERS = {'ANY': <function Parser.<lambda>>, 'CASE': <function Parser.<lambda>>, 'IF': <function Parser.<lambda>>, 'NEXT': <function Parser.<lambda>>}
INVALID_FUNC_NAME_TOKENS = {<TokenType.IDENTIFIER: 'IDENTIFIER'>, <TokenType.STRING: 'STRING'>}
FUNCTIONS_WITH_ALIASED_ARGS = {'STRUCT'}
FUNCTION_PARSERS = {'ANY_VALUE': <function Parser.<lambda>>, 'CAST': <function Parser.<lambda>>, 'CONVERT': <function Parser.<lambda>>, 'DECODE': <function Parser.<lambda>>, 'EXTRACT': <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.WHERE: 'WHERE'>: <function Parser.<lambda>>, <TokenType.GROUP_BY: 'GROUP_BY'>: <function Parser.<lambda>>, <TokenType.HAVING: 'HAVING'>: <function Parser.<lambda>>, <TokenType.QUALIFY: 'QUALIFY'>: <function Parser.<lambda>>, <TokenType.WINDOW: 'WINDOW'>: <function Parser.<lambda>>, <TokenType.ORDER_BY: 'ORDER_BY'>: <function Parser.<lambda>>, <TokenType.LIMIT: 'LIMIT'>: <function Parser.<lambda>>, <TokenType.FETCH: 'FETCH'>: <function Parser.<lambda>>, <TokenType.OFFSET: 'OFFSET'>: <function Parser.<lambda>>, <TokenType.FOR: 'FOR'>: <function Parser.<lambda>>, <TokenType.LOCK: 'LOCK'>: <function Parser.<lambda>>, <TokenType.TABLE_SAMPLE: 'TABLE_SAMPLE'>: <function Parser.<lambda>>, <TokenType.USING: 'USING'>: <function Parser.<lambda>>, <TokenType.CLUSTER_BY: 'CLUSTER_BY'>: <function Parser.<lambda>>, <TokenType.DISTRIBUTE_BY: 'DISTRIBUTE_BY'>: <function Parser.<lambda>>, <TokenType.SORT_BY: 'SORT_BY'>: <function Parser.<lambda>>, <TokenType.CONNECT_BY: 'CONNECT_BY'>: <function Parser.<lambda>>, <TokenType.START_WITH: 'START_WITH'>: <function Parser.<lambda>>}
SET_PARSERS = {'GLOBAL': <function Parser.<lambda>>, 'LOCAL': <function Parser.<lambda>>, 'SESSION': <function Parser.<lambda>>, 'TRANSACTION': <function Parser.<lambda>>}
SHOW_PARSERS: Dict[str, Callable] = {}
TYPE_LITERAL_PARSERS = {<Type.JSON: 'JSON'>: <function Parser.<lambda>>}
DDL_SELECT_TOKENS = {<TokenType.L_PAREN: 'L_PAREN'>, <TokenType.WITH: 'WITH'>, <TokenType.SELECT: 'SELECT'>}
PRE_VOLATILE_TOKENS = {<TokenType.CREATE: 'CREATE'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.UNIQUE: 'UNIQUE'>}
TRANSACTION_KIND = {'DEFERRED', 'EXCLUSIVE', 'IMMEDIATE'}
TRANSACTION_CHARACTERISTICS = {'ISOLATION LEVEL READ COMMITTED', 'ISOLATION LEVEL REPEATABLE READ', 'ISOLATION LEVEL READ UNCOMMITTED', 'READ WRITE', 'READ ONLY', 'ISOLATION LEVEL SERIALIZABLE'}
INSERT_ALTERNATIVES = {'FAIL', 'REPLACE', 'ABORT', 'ROLLBACK', 'IGNORE'}
CLONE_KEYWORDS = {'CLONE', 'COPY'}
HISTORICAL_DATA_KIND = {'TIMESTAMP', 'OFFSET', 'STATEMENT', 'STREAM'}
OPCLASS_FOLLOW_KEYWORDS = {'DESC', 'NULLS', 'ASC'}
OPTYPE_FOLLOW_TOKENS = {<TokenType.COMMA: 'COMMA'>, <TokenType.R_PAREN: 'R_PAREN'>}
TABLE_INDEX_HINT_TOKENS = {<TokenType.FORCE: 'FORCE'>, <TokenType.IGNORE: 'IGNORE'>, <TokenType.USE: 'USE'>}
WINDOW_ALIAS_TOKENS = {<TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.JSON: 'JSON'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.APPLY: 'APPLY'>, <TokenType.SOME: 'SOME'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INET: 'INET'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.LEFT: 'LEFT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT256: 'INT256'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.KILL: 'KILL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FINAL: 'FINAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.BIT: 'BIT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ALL: 'ALL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.IS: 'IS'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ROW: 'ROW'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.END: 'END'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.VIEW: 'VIEW'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATE: 'DATE'>, <TokenType.INT: 'INT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MAP: 'MAP'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DIV: 'DIV'>, <TokenType.MONEY: 'MONEY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.DESC: 'DESC'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.XML: 'XML'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.USE: 'USE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UINT: 'UINT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ANY: 'ANY'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UUID: 'UUID'>, <TokenType.IPV6: 'IPV6'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FULL: 'FULL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SET: 'SET'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ASC: 'ASC'>, <TokenType.VAR: 'VAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.CASE: 'CASE'>, <TokenType.FIRST: 'FIRST'>}
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.FUNCTION: 'FUNCTION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.JSON: 'JSON'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.APPLY: 'APPLY'>, <TokenType.SOME: 'SOME'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INET: 'INET'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.LEFT: 'LEFT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT256: 'INT256'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.KILL: 'KILL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FINAL: 'FINAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.BIT: 'BIT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.ANTI: 'ANTI'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ALL: 'ALL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.IS: 'IS'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.END: 'END'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.VIEW: 'VIEW'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATE: 'DATE'>, <TokenType.INT: 'INT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MAP: 'MAP'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DIV: 'DIV'>, <TokenType.MONEY: 'MONEY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.DESC: 'DESC'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.XML: 'XML'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.USE: 'USE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UINT: 'UINT'>, <TokenType.ANY: 'ANY'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UUID: 'UUID'>, <TokenType.IPV6: 'IPV6'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FULL: 'FULL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SET: 'SET'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ASC: 'ASC'>, <TokenType.VAR: 'VAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.CASE: 'CASE'>, <TokenType.FIRST: 'FIRST'>}
ADD_CONSTRAINT_TOKENS = {<TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.PRIMARY_KEY: 'PRIMARY_KEY'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>}
DISTINCT_TOKENS = {<TokenType.DISTINCT: 'DISTINCT'>}
NULL_TOKENS = {<TokenType.NULL: 'NULL'>}
UNNEST_OFFSET_ALIAS_TOKENS = {<TokenType.FUNCTION: 'FUNCTION'>, <TokenType.TSRANGE: 'TSRANGE'>, <TokenType.ISNULL: 'ISNULL'>, <TokenType.USMALLINT: 'USMALLINT'>, <TokenType.VARIANT: 'VARIANT'>, <TokenType.OVERWRITE: 'OVERWRITE'>, <TokenType.JSON: 'JSON'>, <TokenType.EXISTS: 'EXISTS'>, <TokenType.NCHAR: 'NCHAR'>, <TokenType.ESCAPE: 'ESCAPE'>, <TokenType.NUMRANGE: 'NUMRANGE'>, <TokenType.NVARCHAR: 'NVARCHAR'>, <TokenType.LOAD: 'LOAD'>, <TokenType.APPLY: 'APPLY'>, <TokenType.SOME: 'SOME'>, <TokenType.COMMIT: 'COMMIT'>, <TokenType.UTINYINT: 'UTINYINT'>, <TokenType.INET: 'INET'>, <TokenType.AUTO_INCREMENT: 'AUTO_INCREMENT'>, <TokenType.ARRAY: 'ARRAY'>, <TokenType.CACHE: 'CACHE'>, <TokenType.SMALLMONEY: 'SMALLMONEY'>, <TokenType.UINT128: 'UINT128'>, <TokenType.BIGDECIMAL: 'BIGDECIMAL'>, <TokenType.UBIGINT: 'UBIGINT'>, <TokenType.IMAGE: 'IMAGE'>, <TokenType.BOOLEAN: 'BOOLEAN'>, <TokenType.LEFT: 'LEFT'>, <TokenType.MEDIUMTEXT: 'MEDIUMTEXT'>, <TokenType.SUPER: 'SUPER'>, <TokenType.DELETE: 'DELETE'>, <TokenType.INDEX: 'INDEX'>, <TokenType.INT256: 'INT256'>, <TokenType.CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'>, <TokenType.REPLACE: 'REPLACE'>, <TokenType.GEOMETRY: 'GEOMETRY'>, <TokenType.EXECUTE: 'EXECUTE'>, <TokenType.MODEL: 'MODEL'>, <TokenType.KILL: 'KILL'>, <TokenType.ORDINALITY: 'ORDINALITY'>, <TokenType.FINAL: 'FINAL'>, <TokenType.IPV4: 'IPV4'>, <TokenType.HLLSKETCH: 'HLLSKETCH'>, <TokenType.DICTIONARY: 'DICTIONARY'>, <TokenType.PIVOT: 'PIVOT'>, <TokenType.BIT: 'BIT'>, <TokenType.IPPREFIX: 'IPPREFIX'>, <TokenType.COLUMN: 'COLUMN'>, <TokenType.CURRENT_USER: 'CURRENT_USER'>, <TokenType.DEFAULT: 'DEFAULT'>, <TokenType.ENUM16: 'ENUM16'>, <TokenType.INT4MULTIRANGE: 'INT4MULTIRANGE'>, <TokenType.ROWS: 'ROWS'>, <TokenType.ANTI: 'ANTI'>, <TokenType.TIMESTAMP: 'TIMESTAMP'>, <TokenType.CONSTRAINT: 'CONSTRAINT'>, <TokenType.ALL: 'ALL'>, <TokenType.REFRESH: 'REFRESH'>, <TokenType.IS: 'IS'>, <TokenType.STRUCT: 'STRUCT'>, <TokenType.MERGE: 'MERGE'>, <TokenType.ROW: 'ROW'>, <TokenType.DOUBLE: 'DOUBLE'>, <TokenType.TSMULTIRANGE: 'TSMULTIRANGE'>, <TokenType.TIMESTAMP_S: 'TIMESTAMP_S'>, <TokenType.UDECIMAL: 'UDECIMAL'>, <TokenType.END: 'END'>, <TokenType.TINYINT: 'TINYINT'>, <TokenType.VARBINARY: 'VARBINARY'>, <TokenType.PSEUDO_TYPE: 'PSEUDO_TYPE'>, <TokenType.TRUE: 'TRUE'>, <TokenType.UNIQUE: 'UNIQUE'>, <TokenType.PROCEDURE: 'PROCEDURE'>, <TokenType.OPERATOR: 'OPERATOR'>, <TokenType.TEXT: 'TEXT'>, <TokenType.UNIQUEIDENTIFIER: 'UNIQUEIDENTIFIER'>, <TokenType.LONGBLOB: 'LONGBLOB'>, <TokenType.FALSE: 'FALSE'>, <TokenType.BINARY: 'BINARY'>, <TokenType.IPADDRESS: 'IPADDRESS'>, <TokenType.JSONB: 'JSONB'>, <TokenType.COMMENT: 'COMMENT'>, <TokenType.ROWVERSION: 'ROWVERSION'>, <TokenType.REFERENCES: 'REFERENCES'>, <TokenType.TINYTEXT: 'TINYTEXT'>, <TokenType.FIXEDSTRING: 'FIXEDSTRING'>, <TokenType.OBJECT: 'OBJECT'>, <TokenType.PARTITION: 'PARTITION'>, <TokenType.NESTED: 'NESTED'>, <TokenType.SMALLINT: 'SMALLINT'>, <TokenType.OBJECT_IDENTIFIER: 'OBJECT_IDENTIFIER'>, <TokenType.VIEW: 'VIEW'>, <TokenType.OFFSET: 'OFFSET'>, <TokenType.TSTZRANGE: 'TSTZRANGE'>, <TokenType.DATE: 'DATE'>, <TokenType.INT: 'INT'>, <TokenType.SCHEMA: 'SCHEMA'>, <TokenType.HSTORE: 'HSTORE'>, <TokenType.DATE32: 'DATE32'>, <TokenType.CURRENT_DATE: 'CURRENT_DATE'>, <TokenType.MEDIUMBLOB: 'MEDIUMBLOB'>, <TokenType.SERIAL: 'SERIAL'>, <TokenType.FORMAT: 'FORMAT'>, <TokenType.TIME: 'TIME'>, <TokenType.TIMESTAMP_NS: 'TIMESTAMP_NS'>, <TokenType.UMEDIUMINT: 'UMEDIUMINT'>, <TokenType.MAP: 'MAP'>, <TokenType.BIGINT: 'BIGINT'>, <TokenType.DIV: 'DIV'>, <TokenType.MONEY: 'MONEY'>, <TokenType.VARCHAR: 'VARCHAR'>, <TokenType.UNPIVOT: 'UNPIVOT'>, <TokenType.DESCRIBE: 'DESCRIBE'>, <TokenType.YEAR: 'YEAR'>, <TokenType.DESC: 'DESC'>, <TokenType.CURRENT_DATETIME: 'CURRENT_DATETIME'>, <TokenType.NULLABLE: 'NULLABLE'>, <TokenType.RANGE: 'RANGE'>, <TokenType.TIMETZ: 'TIMETZ'>, <TokenType.VOLATILE: 'VOLATILE'>, <TokenType.INT8RANGE: 'INT8RANGE'>, <TokenType.BIGSERIAL: 'BIGSERIAL'>, <TokenType.CHAR: 'CHAR'>, <TokenType.XML: 'XML'>, <TokenType.INT128: 'INT128'>, <TokenType.NULL: 'NULL'>, <TokenType.RIGHT: 'RIGHT'>, <TokenType.TIMESTAMPTZ: 'TIMESTAMPTZ'>, <TokenType.GEOGRAPHY: 'GEOGRAPHY'>, <TokenType.KEEP: 'KEEP'>, <TokenType.NATURAL: 'NATURAL'>, <TokenType.NUMMULTIRANGE: 'NUMMULTIRANGE'>, <TokenType.SMALLSERIAL: 'SMALLSERIAL'>, <TokenType.WINDOW: 'WINDOW'>, <TokenType.RECURSIVE: 'RECURSIVE'>, <TokenType.LOWCARDINALITY: 'LOWCARDINALITY'>, <TokenType.PRAGMA: 'PRAGMA'>, <TokenType.USE: 'USE'>, <TokenType.FILTER: 'FILTER'>, <TokenType.TEMPORARY: 'TEMPORARY'>, <TokenType.COLLATE: 'COLLATE'>, <TokenType.TIMESTAMPLTZ: 'TIMESTAMPLTZ'>, <TokenType.MEDIUMINT: 'MEDIUMINT'>, <TokenType.DECIMAL: 'DECIMAL'>, <TokenType.OVERLAPS: 'OVERLAPS'>, <TokenType.BEGIN: 'BEGIN'>, <TokenType.FOREIGN_KEY: 'FOREIGN_KEY'>, <TokenType.USERDEFINED: 'USERDEFINED'>, <TokenType.UINT: 'UINT'>, <TokenType.PERCENT: 'PERCENT'>, <TokenType.ANY: 'ANY'>, <TokenType.COMMAND: 'COMMAND'>, <TokenType.UINT256: 'UINT256'>, <TokenType.TSTZMULTIRANGE: 'TSTZMULTIRANGE'>, <TokenType.ENUM: 'ENUM'>, <TokenType.INT4RANGE: 'INT4RANGE'>, <TokenType.DATABASE: 'DATABASE'>, <TokenType.INT8MULTIRANGE: 'INT8MULTIRANGE'>, <TokenType.DATERANGE: 'DATERANGE'>, <TokenType.TOP: 'TOP'>, <TokenType.INTERVAL: 'INTERVAL'>, <TokenType.TINYBLOB: 'TINYBLOB'>, <TokenType.TABLE: 'TABLE'>, <TokenType.UUID: 'UUID'>, <TokenType.IPV6: 'IPV6'>, <TokenType.ENUM8: 'ENUM8'>, <TokenType.CURRENT_TIME: 'CURRENT_TIME'>, <TokenType.FLOAT: 'FLOAT'>, <TokenType.DATEMULTIRANGE: 'DATEMULTIRANGE'>, <TokenType.FULL: 'FULL'>, <TokenType.DATETIME: 'DATETIME'>, <TokenType.UPDATE: 'UPDATE'>, <TokenType.SHOW: 'SHOW'>, <TokenType.NEXT: 'NEXT'>, <TokenType.SEMI: 'SEMI'>, <TokenType.UNKNOWN: 'UNKNOWN'>, <TokenType.SET: 'SET'>, <TokenType.DATETIME64: 'DATETIME64'>, <TokenType.ASC: 'ASC'>, <TokenType.VAR: 'VAR'>, <TokenType.LONGTEXT: 'LONGTEXT'>, <TokenType.SETTINGS: 'SETTINGS'>, <TokenType.TIMESTAMP_MS: 'TIMESTAMP_MS'>, <TokenType.CASE: 'CASE'>, <TokenType.FIRST: 'FIRST'>}
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
SET_REQUIRES_ASSIGNMENT_DELIMITER = True
TRIM_PATTERN_FIRST = False
STRING_ALIASES = False
MODIFIERS_ATTACHED_TO_UNION = True
UNION_MODIFIERS = {'limit', 'offset', 'order'}
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):
1011    def reset(self):
1012        self.sql = ""
1013        self.errors = []
1014        self._tokens = []
1015        self._index = 0
1016        self._curr = None
1017        self._next = None
1018        self._prev = None
1019        self._prev_comments = None
def parse( self, raw_tokens: List[sqlglot.tokens.Token], sql: Optional[str] = None) -> List[Optional[sqlglot.expressions.Expression]]:
1021    def parse(
1022        self, raw_tokens: t.List[Token], sql: t.Optional[str] = None
1023    ) -> t.List[t.Optional[exp.Expression]]:
1024        """
1025        Parses a list of tokens and returns a list of syntax trees, one tree
1026        per parsed SQL statement.
1027
1028        Args:
1029            raw_tokens: The list of tokens.
1030            sql: The original SQL string, used to produce helpful debug messages.
1031
1032        Returns:
1033            The list of the produced syntax trees.
1034        """
1035        return self._parse(
1036            parse_method=self.__class__._parse_statement, raw_tokens=raw_tokens, sql=sql
1037        )

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]]:
1039    def parse_into(
1040        self,
1041        expression_types: exp.IntoType,
1042        raw_tokens: t.List[Token],
1043        sql: t.Optional[str] = None,
1044    ) -> t.List[t.Optional[exp.Expression]]:
1045        """
1046        Parses a list of tokens into a given Expression type. If a collection of Expression
1047        types is given instead, this method will try to parse the token list into each one
1048        of them, stopping at the first for which the parsing succeeds.
1049
1050        Args:
1051            expression_types: The expression type(s) to try and parse the token list into.
1052            raw_tokens: The list of tokens.
1053            sql: The original SQL string, used to produce helpful debug messages.
1054
1055        Returns:
1056            The target Expression.
1057        """
1058        errors = []
1059        for expression_type in ensure_list(expression_types):
1060            parser = self.EXPRESSION_PARSERS.get(expression_type)
1061            if not parser:
1062                raise TypeError(f"No parser registered for {expression_type}")
1063
1064            try:
1065                return self._parse(parser, raw_tokens, sql)
1066            except ParseError as e:
1067                e.errors[0]["into_expression"] = expression_type
1068                errors.append(e)
1069
1070        raise ParseError(
1071            f"Failed to parse '{sql or raw_tokens}' into {expression_types}",
1072            errors=merge_errors(errors),
1073        ) 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:
1110    def check_errors(self) -> None:
1111        """Logs or raises any found errors, depending on the chosen error level setting."""
1112        if self.error_level == ErrorLevel.WARN:
1113            for error in self.errors:
1114                logger.error(str(error))
1115        elif self.error_level == ErrorLevel.RAISE and self.errors:
1116            raise ParseError(
1117                concat_messages(self.errors, self.max_errors),
1118                errors=merge_errors(self.errors),
1119            )

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:
1121    def raise_error(self, message: str, token: t.Optional[Token] = None) -> None:
1122        """
1123        Appends an error in the list of recorded errors or raises it, depending on the chosen
1124        error level setting.
1125        """
1126        token = token or self._curr or self._prev or Token.string("")
1127        start = token.start
1128        end = token.end + 1
1129        start_context = self.sql[max(start - self.error_message_context, 0) : start]
1130        highlight = self.sql[start:end]
1131        end_context = self.sql[end : end + self.error_message_context]
1132
1133        error = ParseError.new(
1134            f"{message}. Line {token.line}, Col: {token.col}.\n"
1135            f"  {start_context}\033[4m{highlight}\033[0m{end_context}",
1136            description=message,
1137            line=token.line,
1138            col=token.col,
1139            start_context=start_context,
1140            highlight=highlight,
1141            end_context=end_context,
1142        )
1143
1144        if self.error_level == ErrorLevel.IMMEDIATE:
1145            raise error
1146
1147        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:
1149    def expression(
1150        self, exp_class: t.Type[E], comments: t.Optional[t.List[str]] = None, **kwargs
1151    ) -> E:
1152        """
1153        Creates a new, validated Expression.
1154
1155        Args:
1156            exp_class: The expression class to instantiate.
1157            comments: An optional list of comments to attach to the expression.
1158            kwargs: The arguments to set for the expression along with their respective values.
1159
1160        Returns:
1161            The target expression.
1162        """
1163        instance = exp_class(**kwargs)
1164        instance.add_comments(comments) if comments else self._add_comments(instance)
1165        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:
1172    def validate_expression(self, expression: E, args: t.Optional[t.List] = None) -> E:
1173        """
1174        Validates an Expression, making sure that all its mandatory arguments are set.
1175
1176        Args:
1177            expression: The expression to validate.
1178            args: An optional list of items that was used to instantiate the expression, if it's a Func.
1179
1180        Returns:
1181            The validated expression.
1182        """
1183        if self.error_level != ErrorLevel.IGNORE:
1184            for error_message in expression.error_messages(args):
1185                self.raise_error(error_message)
1186
1187        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